版权声明:欢迎转载,互相学习。 https://blog.csdn.net/SmalOSnail/article/details/53208867
一个C语言程序从源代码变为最后的可执行文件,需要经历预处理、编译、汇编、链接这四个过程。
这是一般C语言入门书籍上面会提到的,但是很少有人入门时关注这一点,照着书上的代码直接开始码”Hello World.c”。而现在的编译器一般是一步到位,如Dev-cpp
,只需要点一下“编译”就可以把源代码直接变成可执行文件。这样做虽然节约了时间,却不利于新手们从底层开始学习C语言。甚至可能学到最后连什么是预处理、汇编、链接都不清楚,对程序编译的过程没有什么感觉。
在这篇文章中,大家可以通过自己动手实践,逐步地理解、感受c语言的编译过程。
本文使用linux操作环境,windows用户可以安装linux虚拟机或者下载linux模拟器,或者尝试微软的实验功能——linux子系统
- 虚拟机安装教程:
http://wiki.ubuntu.com.cn/虚拟机中安装Ubuntu
- 模拟器下载地址:
http://mingw.org/
- linux子系统安装:
https://linux.cn/article-7209-1.html
文中主要使用gcc
命令以及以下几个参数:
-E Preprocess only; do not compile, assemble or link
-S Compile only; do not assemble or link
-c Compile and assemble, but do not link
-o <file> Place the output into <file>
环境配置好以后,让我们开始c语言的编译之旅吧~
编写c语言源代码
很多linux命令都可以新建一个文件,比如
$ touch test.c
建立一个空白的文件
$ vim test.c
使用vim(文本编辑器)编辑test.c,如果test.c不存在,则创建
$ echo "123" > test.c
通过输出重定向新建一个文件
创建完test.c
后,将下面这段Hello World
代码写到test.c
中(很多方法)
#include <stdio.h>
int main(){
printf("Hello world\n");
return 0;
}
写完之后可以使用ls
命令来查看当前目录下的文件,检查test.c
是否存在
$ ls
使用cat
命令查看test.c中的内容,检查是否写入成功
$ cat test.c
展开头文件(预处理)
$ gcc -E test.c -o test_pre.c
这个命令把源代码test.c中的头文件展开,并把结果输出到test_pre.c
(可以使用cat
或者vim
命令查看test_pre.c
文件中的内容)
test_pre.c
中的内容是这样的,可以发现原本几行的代码变成了几百行,而且已经见不到include
关键字了,取而代之的是一些变量定义的代码,这些代码就是stdio.h
中的内容,和stdio.h
中头文件展开后的内容。
编译
$ gcc -S test_pre.c -o test_asm.s
这一条命令将上一步预处理过后的源代码编译成为汇编代码
现在看到的是test_asm.s里面的汇编代码。
什么是汇编?
汇编语言是汇编指令集、伪指令集和使用它们规则的统称,使用具有一定含义的符号为助忆符,用指令助忆符、符号地址等组成的符号指令称为汇编格式指令。
简单的可以理解为汇编语言是一本词典,01100101011010
这样的二进制字符串是单词,汇编指令是单词的含义。计算机能读懂二进制字符串,而人能读懂的是翻译过来的汇编指令。
汇编
$ gcc -c test_asm.s -o test_obj.o
这一步将test_asm.s
汇编成为目标文件,目标文件中存储的就是010101010
这样的字符串了,可以用cat
命令试试去读取test_obj.o
可以发现打印出来许多不可见的字符,原因是目标文件已经是二进制格式的了,不同于源代码(文本格式)
有关文件的格式可以看下这里的介绍:
http://www.cnblogs.com/zhangjiankun/archive/2011/11/27/2265184.html
链接
链接器负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
- 1
这个例子中没有附加的目标文件,所以只需要目标文件做被链接的对象。
有关链接器的详细讲解大家可以看下这里:
https://www.zhihu.com/question/27386057
$ gcc test_obj.o -o hello
gcc
本身可以充当链接器,这里使用gcc
命令将目标文件test_obj.o
链接成了可执行文件hello
运行程序!
至此,源代码已经经历了预处理、编译、汇编、链接四步成为了可执行文件,现在试着运行一下这个程序吧
$ ./hello
小结
首先我们创建了源文件test.c
,然后用gcc
-E
将源文件中的头文件展开,这一步叫做预处理;
之后通过gcc
-S
将预处理后的源文件编译了汇编代码,这一步叫做编译;
接着使用gcc
-c
命令将汇编代码转换成了二进制的目标文件,这一步操作叫做汇编;
目标文件不同于源代码,是二进制格式,是源文件编译过程中产生的中间文件,通过链接器可以将多个目标文件链接成为可执行文件,这一步叫做链接。
源文件->(预处理->编译->汇编->链接)->可执行文件
一般大家所说的c语言编译,其实是上述这四步的简称。