C++程序的编译过程
预处理
预处理过程实质上是处理“#”,将#include包含的头文件直接拷贝到hell.c当中;将#define定义的宏进行替换,同时将代码中没用的注释部分删除等
具体做的事儿如下:
(1)将所有的#define删除,并且展开所有的宏定义。说白了就是字符替换
(2)处理所有的条件编译指令,#ifdef #ifndef #endif等,就是带#的那些
(3)处理#include,将#include指向的文件插入到该行处
(4)删除所有注释
(5)添加行号和文件标示,这样的在调试和编译出错的时候才知道是是哪个文件的哪一行
(6)保留#pragma编译器指令,因为编译器需要使用它们。
gcc -E hello.c -o a.c
可以生成预处理后的文件。通过查看文件内容和文件大小可以得知a.c讲stdio.h和stdlib.h包含了进来。
编译
编译的过程实质上是把高级语言翻译成机器语言的过程,即对a.c做了这些事儿
(1)词法分析,
(2)语法分析
(3)语义分析
(4)优化后生成相应的汇编代码
从 高级语言->汇编语言->机器语言(二进制)
gcc -S hello.c -o a.s
可以生成汇编代码
gcc -c hello.c -o a.o
将源文件翻译成二进制文件。类Uinx系统编译的结果生生成.o文件,Windows系统是生成.obj文件。
编译的过程就是把hello.c翻译成二进制文件。
链接
就像刚才的hello.c它使用到了C标准库的东西“printf”,但是编译过程只是把源文件翻译成二进制而已,这个二进制还不能直接执行,这个时候就需要做一个动作,
将翻译成的二进制与需要用到库绑定在一块。打个比方编译的过程就向你对你老婆说,我要吃雪糕。你只是给你老婆发出了你要吃雪糕的诉求而已,但是雪糕还没有到。
绑定就是说你要吃的雪糕你的老婆已经给你买了,你可以happy。
gcc hello.c -o a
可以生成可执行程序。即gcc不带任何参数。ldd就可以看到你的可执行程序依赖的库。
可以通过命令,分别查看.s .o 以及可执行程序文件的大小。
可以看到a.o的大小是1.1k,毕竟他只是把源文件翻译成二进制文件。a却有7k,应该是他多了很多“绳子”吧。在运行的时候这些“绳子”就将对应的库函数“牵过来”。很形象的比喻是不是?哈哈。libc.so.6 中就对咱们用的printf进行了定义。
- 本文链接:http://katherineleeyq.cn/2017/11/05/C-程序的编译过程/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!