使用g++编译c/c++程序时,假设程序无错,我们通常直接使用以下命令:
001
|
g++ hello.cpp
|
这样系统会自动生成默认可执行文件a.out.
或者使用
001
|
g++ -o hello hello.cpp
|
则会生成一个可执行文件hello.
同时我相信很多人使用Visual C++时候,都是直接点击Run或者Debug,然后去看返回的错误,至于是哪个过程出错了,有很多人根本没有试过去搞明白,他们习惯去折腾代码本身而对编译器做了什么一无所知,我认为这样的编程习惯是糟糕的,即使你是VC或者其它IDE使用者,不需要自行编写makefile文件,也应当搞清楚自己所写的程序是如何的一个编译过程.
上图中这一命令虽然简单,实际上却包含了数个过程,这里我们不像讲解编译原理一样去分析C++程序的编译过程,在这里我们可以分解为四个步骤:
- 预处理(Prepressing)
- 编译(compilation)
- 汇编(Assembly)
- 链接(Linking)
一 . 预处理的过程主要处理包括以下过程:
- 将所有的#define删除,并且展开所有的宏定义
- 处理所有的条件预编译指令,比如#if #ifdef #elif #else #endif等
- 处理#include 预编译指令,将被包含的文件插入到该预编译指令的位置。
- 添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。
- 保留所有的#pragma编译器指令,因为编译器需要使用它们
通常使用以下命令来进行预处理:
001
|
g++ -E hello.c -o hello.i
|
参数-E表示只进行预处理或者也可以使用以下指令完成预处理过程
cpp hello.c > hello.i
直接cat hello.i 你就可以看到预处理后的代码
二. 编译的过程
就是把预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码.
使用以下命令进行编译:
001
|
g++ -S hello.i -o hello.s
|
编译后的程序hello.s是一个汇编语言的程序,你可以打开看看里面的内容是各种类似于mov,sub之类的汇编指令.
三 . 汇编的过程
则是将汇编代码转换成机器可以执行的指令,我们通过调用汇编器as来完成
001
|
as hello.s -o hello.o
|
或者使用以下命令也行,g++会自动调用as程序
001
|
g++ -c hello.s -o hello.o
|
汇编将输出一个目标文件hello.o
四.链接的过程
则通过调用链接器ld来链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件.
在这里顺便讲一下静态链接和动态链接的概念。静态链接是指在编译阶段直接把静态库加入到可执行文件中去,这样可执行文件会比较大.而动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去.
本文只是很粗略地介绍了一下这个过程,之后也会就每个环节深入的研究,文章中若有不妥之处,还敬请留言指出.