【C语言】编译与链接

1.翻译环境与运行环境

在ANSI C的任何一种实现中,存在两个不同的环境。

1.翻译环境,在这个环境中源代码被转换为可执行的机器指令(二进制指令)

2.执行环境,它用于实际执行代码

 

 2.翻译环境

那么翻译环境是怎么将源代码转换为可执行的机器指令的呢?这里我们就得展开讲解一下翻译环境所做的事情。

其实翻译环境由编译链接两个大的过程组成,而编译又可以分解成三个部分:预处理(也叫预编译)、编译、汇编。

一个C语言的项目中可能由多个.c文件一起构建

多个.c文件生成可执行程序又可分为一下几个步骤:
多个. c文件单独经过编译器,编译处理生成对应的目标文件(在windows环境下目标文件的后缀是.obj,Linux环境下目标文件的后缀是.o)。

多个目标文件和链接库一起经过链接处理生成最终的可执行程序(链接库是指运行库(它是支持程序运行的基本函数集合)或者第三方库)。

如果再把编译器展开成三个过程,那就变成了下面的过程:

2.1 预处理(预编译)

在预处理阶段,源文件和头文件会被处理为.i为后缀的文件。

gcc环境下观察一下,对test.c文件预处理后的.i文件,命令如下:

gcc  -E  test.c  -o test.i

预处理阶段主要处理那些源文件中#开始的预处理指令,比如:#include,#define,处理的规则如下:

将所有的#define删除,并展开所有的宏定义。

处理所有的条件编译指令,如#if,#iddef,#elif,#endif

处理#include预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。

删除所有的注释(也就是你对代码的解释,即//后面的文字)

比如:

test.c中的代码为:

#include<stdio.h>
int main()
{
    printf("hello world");//打印hello worle
    return 0;
}

在生成的test.i中就会把注释删掉

添加行号和文件名标识,方便后续编译器生成调试信息等。

或保留所有的#pragma的编译器指令,编译器后续会使用。

经过预处理后的.i文件中不在包含宏定义,因为宏已经被展开。并且包含头文件都被插到.i 文件中。所以当我们无法知道宏定义或者头文件是否被正确包含的时候,可以查看预处理的.i文件来确认。

 2.2 编译

编译过程就是将预处理后的文件进行一系列的·:词法分析、语法分析、语义分析及优化,生成相应的汇编代码文件。

编译过程的命令如下:

gcc -S test.i -o test.s

 那么对下面代码进行编译的时候,会这么做呢?

array[index]=(index+4)*(2+6)

首先对其进行词法分析 

将源代码程序被输入扫描器,扫描器的任务就是简单的进行词法分析,将代码中的字符分割成一系列的记号(关键字、标识符、字面量、特殊字符等)。

对上面代码进行词法分析得到了16个记号:

接下来进行语法分析:

语法分析器将对扫描产生的记号进行语法分析,从而产生语法树。这些语法树是以表达式为节点的树。

最后进行语义分析:

语义分析器来完成语义分析,即对表达式的语法层面分析。编译器所能做的分析是语义的静态分析。静态语义分析通常包括声明和类型的匹配、类型的转换等。这个阶段会报告错误的语法信息。

(如果想要进一步了解编译过程,可以去看看《编译原理》这一本书) 

2.3 汇编

汇编器是将汇编代码转变成为机器可执行的指令,每一个汇编语句几乎都对应一条机器指令(二进制指令)。就是根据汇编指令和机器指令的对照表一一的进行翻译,也不做指令优化。

汇编的命令如下:

gcc -c test.s -o test.o

2.4 链接

链接是一个复杂的过程,链接的时候需要把一堆文件链接在一起才可以生成可执行程序。

链接过程主要包括:地址和空间分配,符号决议和重定义等这些步骤。

链接解决的是一个项目多文件、多模块之间相互调用的问题。

比如:

在一个c项目中有两个.c文件(test.c和add.c),代码如下:
test.c:

#include <stdio.h>
//test.c
//声明外部函数
extern int Add(int x, int y);
//声明外部的全局变量
extern int g_val;
int main()
{
 int a = 10;
 int b = 20;
 int sum = Add(a, b);
 printf("%d\n", sum);
 return 0;
}

add.c:

int g_val = 2022;
int Add(int x, int y)
{
 return x+y;
}

 我们已经知道,每个源文件都是单独经过编译器处理形成对应的目标文件。

test.c经过编译处理生成test.o

add.c经过编译处理生成add.o

我们在test.c文件中使用了add.c文件中的Add函数和g_val变量。

我们在test.c文件每一次使用Add函数和g_val的时候必须确切的知道Add和g_val的地址,但是由于每个文件是单独编译的,在编译器编译test.c的时候并不知道Add函数和g_val变量的地址,所以暂时把Add的指令的目标地址和g_val的地址搁置。等待最后链接的时候由编译器等根据引用的符号Add在其他模块查找Add函数的地址,然后将test.c中所有引用到Add的指令重新修正,让他们的目标地址成为真正的Add函数的地址,对于全局变量g_val也是类似的方法来修正地址。这个地址修正的过程也被叫做:重定位。

3. 运行环境

1.程序必须载入内存中。在由操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。

2.程序开始执行代码。接着使用main函数。

3.开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数局部变量和返回值地址。程序同时也可以使用静态(static)内存,存储于静态变量在程序的整个执行过程一直保留他们的值。

4.终止程序。正常终止main函数,也有可能时意外终止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/580856.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux(文件系统和日志分析)

目录 1.inode & block​编辑 1.1 inode的内容 1.3 inode的号码 1.4 inode的大小 1.5 inode的特殊作用 1.6 模拟inode号被占满 2. 链接文件 3.文件恢复 3.1 修复EXT类型的文件 3.1.1 EXT类型文件恢复步骤 3.2 修复XFS类型的文件 1.inode & block 1.1 in…

算法应用实例:最大子列和问题

给定N个整数的序列{A1,A2,……AN}&#xff0c;求函数的最大值。 分析&#xff1a;求该序列中最大的连续子列和&#xff0c;若函数最后为负数&#xff0c;返回0作为程序结束。 1.算法1 /*命名为MaxSubseqSum1&#xff0c;A[]:输入整数序列&#xff0c;N&#xff1a;整数序列里面…

7-29 删除字符串中的子串

题目链接&#xff1a;7-29 删除字符串中的子串 一. 题目 1. 题目 2. 输入输出样例 3. 限制 二、代码&#xff08;python&#xff09; 1. 代码实现 str1 input().split(\n)[0] str2 input().split(\n)[0] while str2 in str1:str1 str1.replace(str2, "") // 删…

第4篇:创建Nios II工程之Hello_World<三>

Q&#xff1a;接着我们再来完成Nios II软件工程设计部分。 A&#xff1a;从Quartus Tools选择Nios II Software Build Tools for Eclipse&#xff0c;打开Nios II SBT软件&#xff0c;Workspace指定到hello_world工程的software文件夹路径&#xff1b;再从File-->New-->…

使用STM32CubeMX对STM32F4的CAN1/2/3配置及接收中断开启

目录 1. CAN配置1.1引脚&#xff08;STM32F413VGT6-LQFP100&#xff09;1.2 时钟1.3 RCC配置1.4 CAN1配置1.5 CAN2配置1.6 CAN3配置1.7 输出设置 2. CAN代码2.1 CAN初始化2.2 CAN滤波器设置2.3 CAN使能2.4 激活中断2.5 CAN发送函数2.6 CAN回调函数2.7 main之后的代码 1. CAN配置…

数据分析:生存分析原理和应用实例

介绍 生存分析的目的是分析某个时间点的“生存概率”是多少。基于这样的研究目的,需要提供生存数据,它是一种由不同的开始时间和结束时间组成的事件-时间的数据,比如在癌症研究领域,研究手术到死亡的过程、治疗到疾病进展等等。 在开展生存分析前,需要了解什么是删失(c…

二维码门楼牌管理应用平台建设:隐患统计与智能管理

文章目录 前言一、二维码门楼牌管理应用平台概述二、隐患统计功能的重要性三、隐患统计的实现方式四、隐患统计的实践应用五、面临的挑战与未来发展 前言 随着城市管理的不断升级&#xff0c;二维码门楼牌管理应用平台已成为现代城市管理的重要工具。该平台通过集成先进的信息…

WCH RISC CH32V303RCT6 单片机的SDI Printf 虚拟串口功能 类似SEGGER RTT打印功能 简单分析

参考&#xff1a; 有关于 SDI printf 更多的信息和资料吗&#xff1f; 关于 CH32 系列 MCU SDI 虚拟串口功能的使用 【CH32X035 评估板测评】 教你使用 SDI 接口重定向 printf SDI (Serial Data Interface) 是沁恒微电子 RISC-V 内核的私有外设接口,CH32 RISC-V 系列目前提供了…

PDCA循环:持续精进的工具

文章目录 一、什么是PDCA二、PDCA的应用场景三、PDCA在信息系统项目管理中的应用 一、什么是PDCA PDCA循环是由美国质量管理专家沃特阿曼德休哈特&#xff08;Walter A. Shewhart&#xff09;在20世纪30年代提出的&#xff0c;最初用于制造业的质量管理。休哈特博士在构想PDCA…

二极管钳位型三电平SVPWM(羊角波)闭环系统simulink建模与仿真

整理了二极管钳位型三电平SVPWM&#xff08;羊角波&#xff09;闭环系统simulink建模与仿真模型&#xff0c;附赠参考资料。 在二极管钳位型三电平SVPWM中&#xff0c;通过控制逆变器的开关器件&#xff08;IGBT&#xff09;的导通和关断&#xff0c;将输入的直流电压转换为三…

知网怎么查重 知网查重的详细步骤

知网查重八个步骤&#xff1a;1. 访问官网&#xff0c;注册账号。2. 上传待查文档。3. 选择查重规则。4. 选择相似来源库。5. 提交查重任务。6. 等待查重结果。7. 获取查重报告。8. 下载查重报告。 知网查重的详细步骤 第一步&#xff1a;进入知网查重系统 打开浏览器&#x…

怎样将便签软件搬家?便签迁移攻略

便签软件已成为我们日常生活中不可或缺的记录工具。无论是重要的工作内容&#xff0c;还是琐碎的生活事务&#xff0c;我们都会在便签中一一记下。然而&#xff0c;当我们需要更换电脑或其他设备时&#xff0c;如何将这些珍贵的便签内容迁移到新设备上&#xff0c;成为了许多人…

2024全国大学生高新技术竞赛——算法智星挑战赛 解题报告(流水账版) | 珂学家

前言 评价 因为第一届的缘故吧&#xff0c;导致这场比赛异常的简单。所以不太好评价这块。 怎么说呢&#xff1f; 体验有点差 题目难度没有区分度有两题还存在SPJ判定问题&#xff0c;导致赛时没一人过。 题目分布&#xff0c;简单题占大部分&#xff0c;中等级占一小部分&…

Ubuntu查看端口状态

完蛋了&#xff0c;好像动心了&#xff0c;近一周吃啥东西都索然无味&#xff0c;这可如何是好&#xff01;&#xff01;&#xff01;不知道在期待什么&#xff0c;恐惧与窃喜—— 在Ubuntu系统中&#xff0c;查看某个端口是否被放行&#xff08;即允许流量通过&#xff09;&am…

【JAVA进阶篇教学】第六篇:Java线程中状态

博主打算从0-1讲解下java进阶篇教学&#xff0c;今天教学第六篇&#xff1a;Java线程中状态。 理解并掌握线程的休眠、停止和挂起等操作是多线程编程中的重要内容。下面我将详细说明这些操作&#xff0c;并提供相应的代码案例。 目录 一、线程休眠&#xff08;Thread Slee…

一个早安寄语打卡的小程序技术分享

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 1.早起打卡还能赚钱&#xff1f; 是的&#xff0c;你没有听错&#xff0c;最近发现了个非常有意思的小程序&#xff0c;主要是让用户早起早睡&#xff0c;然后每天进行打卡操作的。 当然&…

【KG+RAG 论文】医学知识图谱检索增强 LLM 的框架 —— KG-RAG

论文&#xff1a;Biomedical knowledge graph-enhanced prompt generation for large language models ⭐⭐⭐ Code&#xff1a;github.com/BaranziniLab/KG_RAG 文章目录 论文速读模型效果总结 论文速读 这篇论文提出了 KG-RAG 的框架&#xff0c;使用医学知识图谱&#xff0…

黑马面试篇

课程地址&#xff1a;新版Java面试专题视频教程&#xff0c;java八股文面试全套真题深度详解&#xff08;含大厂高频面试真题&#xff09;_哔哩哔哩_bilibili 课程名称&#xff1a;新版Java面试专题视频教程&#xff0c;java八股文面试全套真题深度详解&#xff08;含大厂高频…

【Protobuf】protobuf详细介绍

protobuf详细介绍 一、前言二、Protobuf简介2.1、核心思想2.2、Protobuf是如何工作的&#xff1f;2.3、如何使用 Protoc 生成代码&#xff1f;2.4 入门命令 一、前言 在以往的项目中进行网络通信和数据交换的应用场景中&#xff0c;最经常使用的技术便是json或xml。随着JSON的…

用户中心 -- 插件使用 插件使用思路

易错注意点 1 5.1启动类 & 入口类 需保持一致 网址&#xff1a; 第一节课&#xff0c;用户管理--后端初始化&#xff0c;项目调通。二次翻工2-CSDN博客 一、 用户管理 框架 网址&#xff1a; 用户管理 --汇总 -- 明细-CSDN博客 1.2 更改路径&#xff0c;并生效 网址…