我们在linux中编译c代码的时候,都会使用gcc ***.c -o ***可是这一条简简单单的命令后隐藏着什么呢?在输入这条命令,敲击回车之后有发生了什么呢?
首先,gcc的编译过程大体上可以分成4个部分:预编译,汇编,编译,和链接。下面具体说明这些步骤主要时做了什么。
1,预编译,我们在写程序的时候一般会使用include,会使用宏定义define,使用编译选项。这些语句的处理都是在预编译的时候解决的。具体来讲,预编译删除#define,展开所有的宏定义,预编译处理#ifdef #endif等编译指令,预编译处理#include指令,会通过环境变量或者编译指定的参数找到对用的头文件的完整路径,对include的处理使用了递归处理,预编译还会删除注释,增加行号。但是对于#pragma命令,预编译不做处理,因为这条指令编译器还会用到。
可以使用gcc -E ***.c产生预编译后的 ***.i 文件;
2, 编译, 编译过程是将预处理后的文件进行一系列的操作,最终生成汇编代码的过程。这个过程时整个程序构建的核心部分。这之中包括了几个重要的步骤,词法分析,语法分析,中间语言生成,目标代码生成与优化。需要特别声明的是优化过程,编译器时保守的,在优化过程中为了保证程序运行的正确性,在某些可以优化的地方编译器却没有执行优化,这就要求程序员尽可能优化自己的代码。但是即便如此,仍然存在过度优化的可能行,例如在多处理系统中,多个cpu引用同一个变量,为了提高速度变量可能缓存到寄存器中而没有被及时写回,这时候就有可能引发线程错误。同时在优化的过程中编译器有可能会修改指令的执行顺序,这也存在潜在的危险。
可以使用gcc -S ***.c -0 ***.s产生编译后的文件
3,汇编,汇编就是将汇编语言编程机器码的过程,汇编的过程相对简答,每一条汇编代码都对应着一个机器码,在汇编过程中一一对应的可以了。
可以使用as ***.s -o ***.o 或者可以使用 gcc -c ***.s -o ***.o
4,链接,链接是和编译一样讨厌的一个过程,其中牵扯了很多的内容。链接就是将多个目标文件整合成一个可执行文件的过程。其中分为动态链接和静态链接。静态链接时将多个.o文件整合到一个可执行文件中,这个可执行文件不依赖任何的外部库。动态链接是在程序装载的时候中完成的,它是将可执行文件与.so(linux)在装载过程中进行链接,这样可以使动态库可以进行共享,节省了内存和硬盘的空间。关于静态链接和动态链接会在后续的博客中继续说明。
原文:http://blog.csdn.net/gaoxiang__/article/details/44600831