目录
一、安装gcc/g++
gcc/g++ -v : 用来查看当前你使用的gcc/g++版本
因为我的gcc/g++是升级过的所以版本更高,如果你用的是centos7.6的话你的gcc的版本可能是4.8的。
安装gcc/g++:sudo yum install -y gcc-c++
这条指令会根据你当前的centos版本为你安装合适的gcc/g++版本。
gcc用来编译C语言代码,g++一般用来编译C++代码当然也可以用来编译C语言代码
二、背景知识
在生成一个可执行程序文件的时候通常要经过如下几步:
- 预处理(a.去注释 b.宏替换 c.头文件展开 d.条件编译……)
- 编译(生成汇编)
- 汇编(生成机器可识别的代码)
- 链接(生成可执行文件或库文件)
三、相关选项
-E | 从现在开始进行程序的翻译,如果预处理完成,就停下来 |
-S | 从现在开始进行程序的翻译,如果编译完成,就停下来 |
-c | 从现在开始进行程序的翻译,如果汇编完成,就停下来 |
-o | 文件输出到文件 |
-static | 对生成的文件采用静态链接 |
-g | 生成调试信息 |
-shared | 对生成的文件采用动态链接 |
-O0 | 不做任何优化 |
-O1 | 尝试优化编译时间和可执行程序大小 |
-O2 | 在O1的基础上进行更大力度的优化 |
-O3 | 最高级别优化 |
-w | 不生成任何警告信息 |
-Wall | 生成所有警告信息 |
四、gcc如何工作
1.预处理
- 预处理的功能主要包括宏替换,去注释,条件编译,头文件展开等。
- 预处理的指令是以#号开头的代码行。
- 指令:gcc -E mytest.c -o mytest.i
- -E选项是从现在开始进行程序的翻译,如果预处理完成,就停下来。
- -o选项是指目标文件。
- ".i"文件是已经预处理过的C语言原始程序
#include <stdio.h>
#define NUM 20
int main()
{
printf("NUM: %d\n", NUM);
printf("hello world1\n");
// printf("hello world2\n");
// printf("hello world3\n");
// printf("hello world4\n");
// printf("hello world5\n");
printf("hello world6\n");
//条件编译
#ifdef DEBUG
printf("hello debug!\n");
#else
printf("hello release!\n");
#endif
return 0;
}
通过指令:gcc -E mytest.c -o mytest.i
生成了一个mytest.i的文件,我们查看这个文件的内容如下
这里我只截取了一部分,前面还有很多是头文件展开的内容。从这一部分我们不难看出预处理所做的工作。
2.编译
- 在这个阶段中,gcc首先要检查代码的规范性以及是否有语法错误等等,检查无误后,gcc才会把代码翻译成汇编语言。
- 指令:gcc -S mytest.i -o mytest.s
- -S选项是从现在开始进行程序的翻译,如果编译完成,就停下来。
执行上面的指令后生成的“.s”文件内容如下
3.汇编
- 此阶段是把编译阶段生成的".s"文件转成目标文件
- 指令:gcc -c mytest.s -o mytest.o
- -c选项是从现在开始进行程序的翻译,如果汇编完成,就停下来。
举个栗子:
执行上面的指令生成的mytest.o文件称为可重定向目标文件,可以查看这个文件的内容如下
这里显示的都是乱码,我们也可以用od mytest.o进行查看,翻译过来都是二进制
4.链接
- 在成功编译之后,就进入了链接阶段
- 指令:gcc mytest.o -o mytest
- 生成的mytest文件即为可执行程序
5.函数库的概念
首先看一个例子:
这个代码能编译通过吗?
答案是:可以的
因为它自动给你链接上了C语言的库
再看一个例子:
问:在上面的C语言代码中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?
答:系统把这些函数实现都被弄到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用
上面中的 /lib64/libc-2.17.so 提供C语言的方法实现,/usr/include/stdio.h 提供C语言的方法列表,方法的声明。两者协同生成可执行程序。
6.动静态库
一般链接的过程是有两种方式的:
a.动态链接 — 需要动态库
b.静态链接 — 需要静态库
在Linux中以.so结尾的称为动态库,.a结尾的为静态库
在Windows中以.dll结尾的为动态库,.lib结尾的为静态库
查看方式有两种:ldd+可执行程序文件名/file+可执行程序文件名
- 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
- 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面图所示的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。 gcc test.o –o test
- gcc/g++默认生成的二进制程序是动态链接的,这点可以通过 file 命令验证
由图可以看出,静态链接的文件比动态链接的文件大得多了。
安装静态库的命令
C语言静态库安装:sudo yum install -y glibc-static
C++静态库安装:sudo yum install -y libstdc++-static
这次的内容就分享到这了,如有写的不好的地方还请指正,创作不易,如果你觉得写的好的话,就给博主三连吧,你的支持将是我的动力
谢谢!!!