一个C代码到一个可执行程序,其中经历了预编译、编译和链接过程,最终生成可执行程序。
1、编辑源代码hello.c
#include <stdio.h> #define HELLO "Hello World! " #define TEST int main(void){ #ifdef TEST printf(HELLO); #endif return 0; }
2、进行预编译
预编译也叫预处理,本质上就是处理带‘#’的部分和注释,包括以下几部分:
1)删除所有的注释。
2)将#include包含的头文件直接拷贝到hello.c文件中。
3)将所有的宏定义展开,也就是把所有的宏替换掉,并将#define删除。例子中是将printf中的HELLO用"Hello World! "进行了替换,最终是printf("Hello world! ");。
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 -lh total 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 -lh total 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 -lh total 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 -lh total 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程序是所经历的过程。当然可以在分细一点:预处理、编译、汇编、链接。还可以在分一下就是:预编译、编译、优化程序、汇编、链接。大体上就编译和链接两个阶段。