linux编译器:gcc/g++的使用
原文连接:https://blog.csdn.net/weixin_72060925/article/details/131274627
原文链接:https://blog.csdn.net/qq_65207641/article/details/128629904
一、编辑器与编译器的区别
vim是代码编辑器,代码编辑器的功能是让我们输入代码的。所以从这个角度出发,我们常见的记事本也可以算作一个代码编辑器,只不过这个编辑器没有高亮等功能。而我们今天介绍的代码编译器的功能是把编辑器中写入的代码翻译为机器能够听懂的语言并生成可执行文件。所以这二者是有本质区别的。
gcc是用来编译C语言代码的,g++是用来编译C++代码的。这两个编译器在指令和编译过程等方面几乎是一样的。
二、C语言编译的过程
- 预处理(进行头文件展开,条件编译,宏替换,去注释等,最后生成 .i类型的文件)
- 编译(将C语言生成汇编语言,最后生成 .s类型的文件)
- 汇编(将C语言生成可重定位的目标二进制文件,最后生成 .o类型的文件)
- 链接(将 .o文件与库文件某种合并生成可执行程序)
1. 预处理
预处理过程主要作用是将代码中的宏定义进行替换,同时将头文件写入到我们代码的前面,除此以外还会去掉我们写的注释。
g++ -E A.cpp -o A.i
- g++是指我们想要用的编译器是g++
- 选项“-E”,该选项的作用是让 g++ 在预处理结束后停止编译过程。
- “A.cpp”是需要被处理的c++代码。
- 选项“-o”是指要生成的目标文件,“A.i”是我们目标文件的名字,“.i”文件为已经过预处理的C原始程序。
打开hello.i文件:
对比 .c源文件经过预处理之后发现 头文件,条件编译,宏,注释等都被处理了。
2. 编译
以g++为例,在编译阶段,编译器会将预处理过后的C++文件翻译为汇编语言的文件。
g++ -S A.i -o A.s
用vim打开 hello.s
我们可以发现此时c语言代码已经变成了汇编代码,编译完成。
3. 汇编
在汇编阶段,编译器会将编译后的汇编文件翻译为二进制文件。
g++ -c A.s -o A.o
打开hello.o 文件
我们发现一堆乱码,因为汇编之后生成的是机器可识别代码,是我们人类无法理解的,我们无需在意,只需要明白汇编完成就行了。
4.链接(生成可执行文件)
在预处理阶段,编译器会将头文件的内容拷贝到我们写的代码文件中。这里就会有一个问题,头文件中只写了函数的声明,也就是说头文件的作用仅仅是告诉编译器这个函数的的确确存在,但是并没有告诉编译器这个函数到底是怎么实现的,函数的具体实现是写在库文件中的。我们此处介绍的链接其实就是将我们的代码和这些写有函数实现的库文件之间构建联系,从而生成一个可执行文件。
写有函数实现的库文件分为两大类,一类是静态库,一类是动态库。
如果是静态链接的话,编译器就会将静态库中的代码实现拷贝到我们的代码中。这种静态链接的方式有好处也有坏处。好处在于,如果我们的静态库丢失了,由于我们已经对函数实现进行了拷贝,所以代码文件是独立的,依旧可以正常运行。但坏处也显而易见,由于该过程进行了大量的拷贝工作,所以会浪费很多空间。
动态链接则与之相反,动态链接并不会将代码实现进行拷贝,而是和动态库建立一种联系,从而让编译器了解到函数的具体实现。由于很多代码文件都和一个动态库建立联系,所以动态库又叫做共享库。那么这么做有什么优点呢?首先,由于动态链接并不会将代码拷贝到文件中,所以动态链接的方式能够节约大量的空间。缺点也显而易见,如果动态库发生了丢失,那么该文件将无法执行。
g++ A.o -o A
运行一下该程序