一个C代码到一个可执行程序,其中经历了预编译、编译和链接过程,最终生成可执行程序。
1、编辑源代码hello.c
#include#define HELLO "Hello World!\n"#define TESTint main(void){#ifdef TEST printf(HELLO);#endif return 0;}
2、进行预编译
预编译也叫预处理,本质上就是处理带‘#’的部分和注释,包括以下几部分:
1)删除所有的注释。
2)将#include包含的头文件直接拷贝到hello.c文件中。
3)将所有的宏定义展开,也就是把所有的宏替换掉,并将#define删除。例子中是将printf中的HELLO用"Hello World!\n"进行了替换,最终是printf("Hello world!\n");。
4)处理所有的条件编译指令,#ifdef、#ifndef、#endif等。例子中的#ifdef TEST,在预编译的过程中会检查是否定义了TEST这个宏,如果定义了就使用printf这个语句,如果没有定义什么也不做。
5)#pragma特殊的指令,用的很少。
6)添加行号和文件标识(#error、#line)用于调试和编译出错时。
//使用gcc -E hello.c -o hello.i生成预处理后的文件[root@localhost compile_process]# gcc -E hello.c -o hello.i//使用ls -lh看一下文件的大小[root@localhost compile_process]# ls -lhtotal 24K-rw-r--r--. 1 root root 163 Nov 20 11:12 hello.c-rw-r--r--. 1 root root 17K Nov 20 14:46 hello.i
3、编译
编译过程本质上就是把我们编写的代码翻译成机器语言的过程,这个过程都做了以下几步:
1)词法分析
2)语法分析
3)语义分析
4)优化后生成相应的汇编代码
//使用gcc -S hello.c -o hello.s生成汇编代码[root@localhost compile_process]# gcc -S hello.i -o hello.s//ls -lh[root@localhost compile_process]# ls -lhtotal 28K-rw-r--r--. 1 root root 163 Nov 20 11:12 hello.c-rw-r--r--. 1 root root 17K Nov 20 14:46 hello.i-rw-r--r--. 1 root root 347 Nov 20 15:02 hello.s
//使用gcc -c hello.s -o hello.o将汇编文件生成二进制文件也就是机器能识别的语言[root@localhost compile_process]# gcc -c hello.s -o hello.o//ls -lh[root@localhost compile_process]# ls -lhtotal 32K-rw-r--r--. 1 root root 163 Nov 20 11:12 hello.c-rw-r--r--. 1 root root 17K Nov 20 15:08 hello.i-rw-r--r--. 1 root root 856 Nov 20 15:15 hello.o-rw-r--r--. 1 root root 347 Nov 20 15:08 hello.s
4、链接
在编译后只是生成了二进制文件,该文件不是可执行文件,要想得到可执行文件就要把二进制文件和C标准库绑到一起,这就是链接过程了。
//使用gcc hello.o -o hello生成可执行文件hello[root@localhost compile_process]# gcc hello.o -o hello//ls -lh[root@localhost compile_process]# ls -lhtotal 40K-rwxr-xr-x. 1 root root 4.6K Nov 20 15:27 hello-rw-r--r--. 1 root root 163 Nov 20 11:12 hello.c-rw-r--r--. 1 root root 17K Nov 20 15:08 hello.i-rw-r--r--. 1 root root 856 Nov 20 15:15 hello.o-rw-r--r--. 1 root root 347 Nov 20 15:08 hello.s//执行可执行文件hello[root@localhost compile_process]# ./hello Hello World!//使用ldd查看一下可执行程序所依赖的库信息[root@localhost compile_process]# ldd hello linux-gate.so.1 => (0x00ad9000) libc.so.6 => /lib/libc.so.6 (0x003da000) /lib/ld-linux.so.2 (0x00572000)
这就是我在使用gcc编译C程序是所经历的过程。当然可以在分细一点:预处理、编译、汇编、链接。还可以在分一下就是:预编译、编译、优化程序、汇编、链接。大体上就编译和链接两个阶段。