【C语言】收官之战——文件的编译和连接

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 【C语言】收官之战——文件的编译和连接,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

文件的编译、连接

        一个可执行程序是怎么由源文件生成的?

        这个过程到底经历了什么?

废话不多讲,就从如下代码开始分析:

//test.c文件

#include<stdio.h>

extern int Add(int x, int y);

int main()
{
	int a = 10;
	int b = 6;
	int sum = Add(a, b);
	printf("a + b = %d\n", sum);
	return 0;
}
//Add.c文件
int Add(int x, int y)
{
	return x + y;
}

这段代码从源文件到可执行程序经历了什么?

大体上来说,如下图

 【C语言】收官之战——文件的编译和连接

 可是此段过程编译器到底干了什么事呢?

                                                                没错,编译和连接,继续往下看

【C语言】收官之战——文件的编译和连接

 由于vs2022集成开发环境不易演示每个细节

                                                                        我们用linux gcc来演示编译和链接

先来看看预编译会做什么事:

【C语言】收官之战——文件的编译和连接

这个里的gcc test.c -E是为了编译test.c让其在预编译的时候停下来 

回车一按,会发现屏幕上出现了很多东西,为了方便观察,将他移至test.i文件中,便于观察

【C语言】收官之战——文件的编译和连接

你会发现,忽然就有八百多行的东西

【C语言】收官之战——文件的编译和连接

这是什么呢?

对比一下之前的代码,不难发现就是将stdio.h里面的东西包含进来了

也就说包含预处理指令,那如果#define MAX 100也会在预编译时也会被替换进来吗

答案是肯定的!

假如定义int z = MAX;会发现,在预编译时MAX就被替换成100

【C语言】收官之战——文件的编译和连接

 不卖关子,实际上也包含了注释删除

 总的来说,预编译实际上就干了这几件事

【C语言】收官之战——文件的编译和连接

 那么有同学会问了,预编译后面的编译阶段停下来,会发生呢?

                                                                                                        往下走~

如果通过gcc test.i -S(停留在编译阶段),就会发现多了如下几个文件

【C语言】收官之战——文件的编译和连接

 同样的方式编译Add.i

【C语言】收官之战——文件的编译和连接

 这个过程实际上会经历这样一个过程,如下图:

【C语言】收官之战——文件的编译和连接

 那么如果你想在汇编阶段停下来,如下

【C语言】收官之战——文件的编译和连接【C语言】收官之战——文件的编译和连接

 回车后:

【C语言】收官之战——文件的编译和连接

【C语言】收官之战——文件的编译和连接

 会发现多了.o文件

        注意:这里说明一点,windows环境下编译出来的目标文件为xxx.obj,linux环境下编译出的目标文件为xxx.o

如果你好奇,打开了test.o文件,就会出现如下场景:

【C语言】收官之战——文件的编译和连接

 哎呀,怎么是这样一堆乱码啊?

                                                实际上这里的目标文件就是二进制文件~

 汇编仅仅是干这件事吗?

                                        远远不知,实际上还会形成符号表

什么是符号表呢?

如下图:

【C语言】收官之战——文件的编译和连接

 总的来说,汇编实际上干了这么一件事:

【C语言】收官之战——文件的编译和连接

汇编完后就会立马进入链接~

                                             接下来会发生什么呢? 

链接链接,自然是要链接一些东西呀,什么呢?

                                                                        还记得之前形成的符号表吗?

咱就是要干这么几件事,如下:

【C语言】收官之战——文件的编译和连接

 怎么链接的呢?

                        实际上会干这么几点事:

                                                                1.合称段表

        test.o和Add.o文件实际上形成各自的段表,这一过程便是将相同的段合并在一起

如下图:

【C语言】收官之战——文件的编译和连接

 接下来还有一步:符号表的合成和重定位

这两部之间到底是怎样的,究竟干了什么?

                                                                实际上如下:

【C语言】收官之战——文件的编译和连接

         实际上就联系起来了啊~

                                                想象一下,如果没有Add.o这个函数主体,只有引入extern Add

假设屏蔽:

【C语言】收官之战——文件的编译和连接

        相当于Add只有那个无效地址,所以如果执行以下代码:

【C语言】收官之战——文件的编译和连接

 运行结果:

【C语言】收官之战——文件的编译和连接

         你会发现,他会在链接期间报错,恰好与刚刚的Add无效地址吻合,这样一个无效的地址在链接形成新的符号表后还是无效地址,也恰好表明Add这个函数不存在,所以程序无法执行通过;

恰好也证明一点:如果没有extern int Add(int , int); 强行执行代码,也可以运行过去,因为Add的有效地址存在;

        也就是说,链接期间干了这么几件事:

【C语言】收官之战——文件的编译和连接

从原理上讲,大致就是这样一个过程~

【C语言】收官之战——文件的编译和连接 

码字不易~ 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129910.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!