浅谈C语言编译与链接

个人主页(找往期文章包括但不限于本期文章中不懂的知识点):我要学编程(ಥ_ಥ)-CSDN博客

翻译环境和运行环境

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

第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令(二进制指令)。 第2种是执行环境,它用于实际执行代码。翻译过程可以理解为机器把我们写的代码转换成它自己看得懂的一个过程。执行过程就是机器把它自己翻译过的代码,按照自己的理解运行起来。

翻译环境 

那翻译环境是怎么将源代码转换为可执行的机器指令的呢?这里我们就得学习一下翻译环境所做的事情。 其实翻译环境是由编译链接两个大的过程组成的,而编译又可以分解成:预处理(也叫预编译)、编译、汇编三个过程。 如下图所示:

⼀个C语言的项目中可能有多个 .c 文件一起构建,那多个 .c 文件如何生成可执行程序呢?

• 多个.c文件分别单独经过编译器,编译处理生成对应的目标文件(注:在Windows环境下的目标文件的后缀是 .obj ,Linux环境下目标文件的后缀是 .o)。

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

下图是Linux环境下,以gcc为例的详细过程。

预处理(预编译)

在预处理阶段,源文件和头文件会被处理成为.i为后缀的文件。 在 gcc 环境下想观察,对 test.c 文件预处理后的.i文件,命令如下:gcc -E test.c -o test.i(是gcc下才能观察)

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

• 将所有 #define 定义的语句或者宏删除,并展开所有的宏定义。

• 处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif 。(这些条件编译指令在文末会介绍)

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

• 删除所有的注释

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

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

经过预处理后的.i文件中不再包含宏定义,因为宏已经被展开。并且包含的头文件都被插入到.i文件 中。所以当我们想知道宏定义或者头文件是否包含正确的时候,可以查看预处理后的.i文件来确认,看看经过预编译后的结果是否符合我们的要求。

编译

编译过程就是将预处理后的文件进行一系列的:词法分析、语法分析、语义分析及优化,生成相应的汇编代码文件。 编译过程的命令如下:gcc -S test.i -o test.s(是gcc下才能观察)

对下面代码进行编译的时候,编译器会怎么做呢?我们就一起来观察:

array[index] = (index+4)*(2+6);//假设我们写了一句这样的代码

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

上面程序进行词法分析后得到了16个记号(如下表):

记号类型
array标识符
[左方括号
index标识符
]右方括号
=赋值
左圆括号
index标识符
+加号
4数字
右圆括号
*乘号
左圆括号
2数字
+加号
6数字
右圆括号

词法分析完之后就是语法分析。接下来语法分析器,将对扫描产生的记号进行语法分析,从而产生语法树。这些语法树是以表达式为节点的树(如下图所示)。

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

汇编 

上述操作进行完之后就代表编译结束了,则开始进行汇编。汇编器是将汇编代码转变成机器可执行的(二进制)指令,每一个汇编语句几乎都对应一条机器指令。就是根据汇编指令和机器指令的对照表一 一的进行翻译,也不做指令优化。 汇编的命令如下:gcc -c test.s -o test.o(gcc下才能观察)

链接

链接是一个复杂的过程,链接的时候需要把一堆文件链接在一起才生成可执行程序。 链接过程主要包括:地址和空间分配,符号决议和重定位等这些步骤。 链接解决的是一个项目中多文件、多模块之间互相调用的问题。假设在一个C的项目中有两个.c文件( test.c 和 add.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 也是类似的方法来修正地址。这个地址修正的过程也被叫做:重定位。

运行环境

1. 程序要运行起来必须要载入内存中。在有操作系统的环境中:一般这个由操作系统完成(例如:我们启动微信,QQ等应用,操作系统会自动加载与其相关的数据,注意我们在写代码运行时也是由操作系统自己完成的)。在独立的环境中,程序的载入必须由手工执行,也可能是通过可执行代码置入只读内存来完成。 2. 程序的执行便开始。接着便调用main函数。 3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack)(也叫函数栈帧),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。 4. 终止程序。正常终止main函数;也有可能是意外终止。

好啦!以上就是C语言编译和链接的大概过程。下一期我们再一起学习吧!

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

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

相关文章

ssh 公私钥(github)

一、生成ssh公私钥 生成自定义名称的SSH公钥和私钥对&#xff0c;需要使用ssh-keygen命令&#xff0c;这是大多数Linux和Unix系统自带的标准工具。下面&#xff0c;简单展示如何使用ssh-keygen命令来生成具有自定义名称的SSH密钥对。 步骤 1: 打开终端 首先&#xff0c;打开我…

增强现实(AR)和虚拟现实(VR)营销的未来:沉浸式体验和品牌参与

--- 如何将AR和VR技术应用于营销&#xff0c;以提高品牌知名度、客户参与度 增强现实&#xff08;AR&#xff09;和虚拟现实&#xff08;VR&#xff09;不再只是游戏。这些技术为品牌与受众互动提供了创新的方式。营销人员可以创造更好的客户体验&#xff0c;并为身临其境的故…

hadoop-3.1.1分布式搭建与常用命令

一、准备工作 1.首先需要三台虚拟机&#xff1a; master 、 node1 、 node2 2.时间同步 ntpdate ntp.aliyun.com 3.调整时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 4.jdk1.8 java -version 5.修改主机名 三台分别执行 vim /etc/hostname 并将内容指定为…

电脑突然死机怎么办?

死机是电脑常见的故障问题&#xff0c;尤其是对于老式电脑来说&#xff0c;一言不合电脑画面就静止了&#xff0c;最后只能强制关机重启。那么你一定想知道是什么原因造成的吧&#xff0c;一般散热不良最容易让电脑死机&#xff0c;还有系统故障&#xff0c;比如不小心误删了系…

【实现报告】学生信息管理系统(顺序表)

目录 实验一 线性表的基本操作 一、实验目的 二、实验内容 三、实验提示 四、实验要求 五、实验代码如下&#xff1a; &#xff08;一&#xff09;顺序表的构建及初始化 &#xff08;二&#xff09;检查顺序表是否需要扩容 &#xff08;三&#xff09;根据指定学生个…

企业网站建设的方法的相关问题的解决办法的问题

现在市场上比较大的公司都建立了自己的企业网站&#xff0c;比如华为、小米等&#xff0c;在他们的企业网站中&#xff0c;可以充分展示自己产品的优势&#xff0c;介绍公司的优质服务。 这都是让顾客改变购买想法的重要因素。 现在互联网发达了&#xff0c;很多人在购买产品的…

详细分析axios.js:72 Uncaught (in promise) Error: 未知错误 的解决方法(图文)

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 调试接口的时候,打开一个网页,在终端出现如下错误: axios.js:72 Uncaught (in promise) Error: 未知错误at __webpack_exports__.default (axios.js:72:1)截图如下所示: 2. 原理分析 点击浏览器的Bug出错: // 如果…

C/C++语言学习路线: 嵌入式开发、底层软件、操作系统方向(持续更新)

初级&#xff1a;用好手上的锤子 1 【感性】认识 C 系编程语言开发调试过程 1.1 视频教程点到为止 1.2 炫技视频看看就行 1.3 编程游戏不玩也罢 有些游戏的主题任务就是编程&#xff0c;游戏和实际应用环境有一定差异&#xff08;工具、操作流程&#xff09;&#xff0c;在…

进程知识点

引用的文章&#xff1a;操作系统——进程通信&#xff08;IPC&#xff09;_系统ipc-CSDN博客 面试汇总(五)&#xff1a;操作系统常见面试总结(一)&#xff1a;进程与线程的相关知识点 - 知乎 (zhihu.com) 二、进程的定义、组成、组成方式及特征_进程的组成部分必须包含-CSDN博…

2024年北京事业单位报名照片要求,注意格式

2024年北京事业单位报名照片要求&#xff0c;注意格式

【C语言】预处理常见知识详解(宏详解)

文章目录 1、预定义符号2、define2.1 define 定义常量2.2 define 定义宏 3、#和##3.1 **#**3.2 **##** 4、条件编译&#xff08;开关&#xff09; 1、预定义符号 在C语言中内置了一些预定义符号&#xff0c;可以直接使用&#xff0c;这些符号实在预处理期间处理的&#xff0c;…

工控安全双评合规:等保测评与商用密码共铸新篇章

01.双评合规概述 2017年《中华人民共和国网络安全法》开始正式施行&#xff0c;网络安全等级测评工作也在全国范围内按照相关法律法规和技术标准要求全面落实实施。2020年1月《中华人民共和国密码法》开始正式施行&#xff0c;商用密码应用安全性评估也在有序推广和逐步推进。…

信息安全之网络安全防护

先来看看计算机网络通信面临的威胁&#xff1a; 截获——从网络上窃听他人的通信内容中断——有意中断他人在网络上的通信篡改——故意篡改网络上传送的报文伪造——伪造信息在网络上传送 截获信息的攻击称为被动攻击&#xff0c;而更改信息和拒绝用户使用资源的攻击称为主动…

深入了解高压电阻器的世界,探索其操作、类型和在各种高压应用中的关键作用

高压电阻器是高压条件下的专用元件&#xff0c;对于管理电压和散热至关重要 它们的工作原理是欧姆定律 类型包括线绕电阻、碳复合电阻、金属氧化物膜电阻、厚膜电阻和薄膜电阻这些电阻器在电力系统、医疗设备、汽车电子和电信设备中是必不可少的。 额定电压从600V到48KV 80p…

fastadmin学习04-一键crud

FastAdmin 默认内置一个 test 表&#xff0c;可根据表字段名、字段类型和字段注释通过一键 CRUD 自动生成。 create table fa_test (id int unsigned auto_increment comment ID primary key,user_id int(10) default 0 null…

基础算法-去重字符串,辗转相除法,非递归前序遍历二叉树题型分析

目录 不同子串 辗转相除法-求最大公约数 二叉树非递归前序遍历 不同子串 从a开始&#xff0c;截取 a aa aaa aaab 从第二个下标开始a aa aab 从第三个 a ab 从第四个 b 使用set的唯一性&#xff0c;然后暴力遍历来去去重&#xff0c;从第一个下标开始截取aaab a aa aaa aaab…

代码随想录算法训练营第36天|738.单调递增的数字|968.监控二叉树|总结

代码随想录算法训练营第36天|738.单调递增的数字|968.监控二叉树|总结 738.单调递增的数字 https://programmercarl.com/0738.%E5%8D%95%E8%B0%83%E9%80%92%E5%A2%9E%E7%9A%84%E6%95%B0%E5%AD%97.html class Solution { public:int monotoneIncreasingDigits(int n) {string s…

R语言批量计算t检验,输出pvalue和均值

1.输入数据如下&#xff1a; 2.代码如下 setwd("E:/R/Rscripts/rG4相关绘图") # 读取CSV文件 data <- read.csv("box-cds-ABD-不同类型rg4-2.csv", stringsAsFactors FALSE)# 筛选出Type2列为指定五种类型的数据 filtered_data <- subset(data, …

【分类评估指标,精确率,召回率,】from sklearn.metrics import classification_report

from&#xff1a; https://zhuanlan.zhihu.com/p/368196647 多分类 from sklearn.metrics import classification_report y_true [0, 1, 2, 2, 2] y_pred [0, 0, 2, 2, 1] target_names [class 0, class 1, class 2] # print(classification_report(y_true, y_pred, targe…

学浪m3u8视频解密

学浪视频在网页上并不是mp4&#xff0c;而是以m3u8进行传输&#xff0c;使用m3u8可以有效解决服务器的压力&#xff0c;而且不仅仅是m3u8&#xff0c;还加密了key&#xff0c;需要逆向key算法得到真实key 下面是学浪m3u8视频解密的工具&#xff0c;全程自动化&#xff0c;不需…
最新文章