目录
程序编译环境程序的执行环境
在ANSI C的任何一种实现中,存在两个不同的环境
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。
C语言程序的编译+链接
不知道大家有没有想过一个问题,
一个C语言的源文件是如何从,“ test.c”----------> "test.exe"可执行文件的呢?
没想明白也不要紧,因为接下来我会跟大家讲明白
源文件 test.c------------------->可执行文件 test.exe,简单的过程如下
如果一个工程了里面有多个.c文件组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索个人
的程序库,将其需要的函数也链接到程序中。
翻译环境
其实test.c------------------->可执行文件 test.exe,中间步骤都是我们的集成开发环境帮我们搞定了,虽然编译器帮我们把源文件.c变成了可执文件.exe,但是我们要知道编译器到底做了那些事情?
如图所示,编译器把test.c文件---------->test.exe文件,编译器经过编译做了三件事情预编译、编译、汇编。
但是它在预编译、编译、汇编、链接的时候都做了什么,想不想知道?
我画了一个图,在linux下面操作,因为vs2019平台不可以,在linux下面展示效果。
在linux平台下,我创建了两个.c文件,Add.c、test.c
第一步:对这个文件用该命令进行预编译,功能参考上图
//预处理编译命令
//完成预处理后保存到test.i和Add.i中
gcc test.c -E > test.i
gcc test.c -E > Add.i
打开test.i文件和tets.c文件对比,圈着的那个地方就是包含头文件,箭头指着的是文件路径,下面的完成宏的替换,注释也不见了,通个两张图片可以看到预编译的时候编译器是做什么工作了吗,所以明白预编译是在干嘛 了吗?
第二步:编译
//命令
gcc -S test.c
gcc -S Add.c
1.看两者区别,是不少了一个分号,所以编译阶段做的事情就是检查分析,检查代码有没有语法的错误,如果有错就报错
看Add函数函数哪里是不是少了一个分号,所以上面的报错信息就是说这里少了一个分号。
如果没有错就会成功生成两个.s文件
2.符号符号汇总,多个.c文件符号单独汇总:
左边是test.c 右边是Add.c
第三步:汇编
//输入命令
gcc -c test.c
gcc -c Add.c
生成.o文件,.o文件和Win平台的.obj目标文件是一样的
1.这一步把c源码翻译成汇编程序,打开.owen文件就是elf格式的了。test.o 和 Add.od的,我们人肯定看不懂了,的是有工具可以看懂,让我们知道里面是什么?工具是resdelfre
//查看二进制内容
readelf -S test.o
readelf -S Add.o
1.这里就识一些符号表,可以通俗嗲就是各种信息地址,下面的地址是我随便给的
那符号表有什么用?
作用:这些符号表,最后我们在最后链接的时候可以通过这些符号和地址去找到对应的函数,因为一个工程可能有多个.c文件,链接的时候通过这些地址到其他源文件找到这些函数。
第四步:链接
合并符号表,并且保留有效的符号,未来我们通过调用这些函数的时候就可以通过这些地址回来找到这些函数。为什么要放弃Add 0x0000这个地址,因为这只是一个声明没有意义所以放弃
最后就得到了一个我们可以个test.out文件,和win下的test.exe一样的。
通过linux说明白了一个源文件test.c---------->可执行test.exe的一个过程,和中间每一个过程都发生什么事情,现在都说清楚了。