一、C程序编译的过程
- 预处理(进行宏替换/去注释/条件编译/头文件展开等)
- 预处理指令是以#号开头的代码行。
- 头文件展开是指:把头文件中的相关内容直接拷贝到源文件中(所以预处理完毕后就不需要用到头文件了)
- 预处理后的文件以 “.i”为后缀。
- 编译(生成汇编代码)
- 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
- 编译后的文件以 “.s”为后缀。
- 汇编(生成机器可识别代码)
- 在这个阶段中,gcc 把汇编代码转化为二进制代码目标文件
- 汇编后的文件以 “.o”为后缀。
- 链接(生成可执行文件或库文件)
- 链接多个目标文件(至少一个)和 库文件 形成可执行文件
二、gcc编译C程序
1.一步到位(直接从c程序文件到可执行程序)
首先得写一个c程序:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 4
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim code.c
- gcc c程序(对c程序进行编译生成名为 a.out 的可执行程序)
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ gcc code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 16
-rwxrwxr-x 1 zh zh 8360 May 10 16:54 a.out
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ./a.out
hello world
- gcc c程序 -o 指定生成的文件名(对c程序进行编译生成指定文件名的可执行程序)
或 gcc -o 指定生成的文件名 c程序(两种写法都能达到同样效果)
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 4
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ gcc code.c -o code
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 16
-rwxrwxr-x 1 zh zh 8360 May 10 16:58 code
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ./code
hello world
2.分步骤拆解(预处理—>编译—>汇编—>链接)
2.1 预处理
gcc -E c文件 -o 生成的文件
(-E 的作用:开始进行c程序的翻译,当预处理阶段完毕后翻译就停止)
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 4
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ gcc -E code.c -o code.i
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 24
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 16872 May 10 17:11 code.i
我们怎么知道生成的 code.i 到底是不是c程序预处理后的文件,打开看看就知道了:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim code.i
发现 code.i 文件竟然变成足足843行,这就是预处理过程中头文件<stdio.h>展开的作用;而且 code.i 文件仍然是c代码,证明还没经过 编译阶段;种种迹象表明 code.i 就是 code.c 只经过预处理后的文件
2.2 编译
gcc -S c文件/预处理后的c文件 -o 生成的文件
(-S 的作用:开始进行c程序的翻译,当编译阶段完毕后翻译就停止)
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 24
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 16872 May 10 17:11 code.i
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ gcc -S code.i -o code.s
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 28
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 16872 May 10 17:11 code.i
-rw-rw-r-- 1 zh zh 447 May 10 19:38 code.s
打开 code.s 文件观察:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim code.s
code.s 文件中的内容是汇编代码,表明 code.s 是 c程序 经过编译阶段后的文件
2.3 汇编
(1)gcc -c c文件/预处理后的c文件/编译后的c文件 -o 生成的文件
(-c 的作用:开始进行c程序的翻译,当汇编阶段完毕后翻译就停止)
(2)gcc -c c文件/预处理后的c文件/编译后的c文件
(汇编后自动生成以 .o 为后缀的同名文件)
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 28
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 16872 May 10 17:11 code.i
-rw-rw-r-- 1 zh zh 447 May 10 19:38 code.s
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ gcc -c code.s -o code.o
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 32
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 16872 May 10 17:11 code.i
-rw-rw-r-- 1 zh zh 1496 May 10 19:45 code.o
-rw-rw-r-- 1 zh zh 447 May 10 19:38 code.s
打开 code.o 文件观察:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ vim code.o
code.o 文件中的内容全是乱码,实际上就是二进制代码,二进制文件得使用专门的方式查看,否则看到得就是乱码。这表明 code.o 是 c程序 经过汇编阶段后的文件
2.4 链接
gcc c文件/预处理后的c文件/编译后的c文件/汇编后的c文件 -o 生成的文件
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 32
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rw-rw-r-- 1 zh zh 16872 May 10 17:11 code.i
-rw-rw-r-- 1 zh zh 1496 May 10 19:45 code.o
-rw-rw-r-- 1 zh zh 447 May 10 19:38 code.s
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ gcc code.o -o code.exe
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ls -l
total 44
-rw-rw-r-- 1 zh zh 75 May 10 16:35 code.c
-rwxrwxr-x 1 zh zh 8360 May 10 20:10 code.exe
-rw-rw-r-- 1 zh zh 16872 May 10 17:11 code.i
-rw-rw-r-- 1 zh zh 1496 May 10 19:45 code.o
-rw-rw-r-- 1 zh zh 447 May 10 19:38 code.s
链接后形成可执行文件,可以直接运行:
[zh@iZbp1dr1jtgcuih41mw88oZ ~]$ ./code.exe
hello world