编译
预处理/预编译
在预处理的时候,编译器会将源代码中的宏定义删除,在代码中使用的宏全部替换,同时取消注释。我们可以在linux环境中利用gcc来调试
查看test.i : cat test.i
可以看到预处理后的文件将头文件直接拷贝到了代码中,删除了注释,并且将MAX以1000进行替换
编译
这一步可以在linux系统中利用 gcc -S test.i -o test.s 进行操作,得到test.s文件,也就是对应的汇编代码,编译器在这一步中需要进行语法分析,词法分析,符号汇总,语义分析。
这就是生成的对应的汇编代码
汇编
这一步在linux上使用 gcc -c test.s -o test.o即可实现,他可以将汇编代码转换成二进制指令,同时形成符号表
test2.c
add.c
对于add.c文件在编译后形成的符号表如下图所示
对于test2.c 文件在编译后形成如下符号表:
到这里编译结束
链接
链接时,会合并段表并且符号表也会合并和重定向,同时调用链接库进行链接。
以上方代码为例test2.c 与 add.c 中的Add会和并,此时add.c中的Add地址是有效值,而test2.c中的Add是无效值,所以就以add.c中的Add地址为主,形成下方的符号表:
如果每个文件中都有一个Add,则链接时,由于每一个Add都会有一个有效地址,此时会报一个链接错误,找到多个函数。
在C++中会根据函数参数和数目的不同进行函数压轧,如 int Add(int a, int b); 符号表中显示 Add_i_i,而 double Add(double a, double b); 在符号表中显示 Add_d_d;
运行
1.程序必须载入到内存中才能运行,在有操作系统的环境中,这个操作一般由操作系统完成。在独立的环境中,程序的载入必须由手工安排,如单片机的烧录程序,也可能是通过可执行代码置入只读内存来完成。
2.程序执行即开始运行,接着便调用main函数
3.开始执行程序代码。这个时候程序将使用一个运行时堆栈,也叫函数栈帧,存储函数的局部变量和返回地址。程序同时也可以使用静态内存,存储于静态内存中的变量在程序的整个执行过程中一直保留他们的值
4.终止程序,正常终止main函数,也有可能是意外终止。比如内存泄露,非法访问,数组越界,停电等。