目录
一、什么是编译器
简单讲,编译器就是将一种语言转化为另一种语言的程序,通常是将高级语言转化为低级语言。一个现代编译器的主要工工作流程:预处理 →编译 →汇编 →链接 ,最终生成可执行程序。
高级计算机语言便于人编写,阅读交流,维护。而机器语言是计算机能直接解读、运行的。编译器将汇编或高级计算机语言源程序作为输入,翻译成目标语言机器代码的等价程序。源代码一般为高级语言, 如C、C++、JAVA等,或者汇编语言,而目标代码则是机器语言的目标代码,也称机器代码。
gcc/g++是C语言和C++语言代码的编译器,因为C++兼容C,所以g++编译器也可以编译C语言代码。本文主要讲述的是gcc编译器的操作和功能。
二、编译的过程
利用gcc编译器一步到位生成可执行文件的命令是:
gcc -o myfile myfile.c 或者 gcc myfile.c -o myfile。
其中的选项-o和生成的可执行文件myfile必须相邻。上述命令是对myfile.c文件进行编译生成可执行文件myfile。
1.预处理
预处理阶段会对程序进行头文件展开、条件编译、宏替换、去注释等操作。生成的文件后缀为 .i
-E 从现在开始对文件进行编译,预处理结束后停止操作。
命令为:gcc -E myfile.c -o myfile.i
同理,其中的选项-o和生成的文件myfile.i必须相邻。
注:
1.头文件展开:
①#include指令使另外一个文件被编译:预处理器先删除这条指令,并用包含文件的内容替换。这样一个文件被包含10次,那就实际被编译10次。文件开头写:#pragma once 可以避免头文件的重复引入。
②库文件一般用 < > 包含;本地文件一般用 “ ” 包含。
2.条件编译:
①#if 指令用于检测后面的常量表达式,如果为真,则编译接下来的代码,直到出现 #else、#elif、#endif为止;否则就不编译。
②#ifdef指令用于检测后面的表达式,如果被定义,编译接下来的代码;#ifndef指令用于检测后面的表达式,如果未被定义,编译接下来的代码。
③#endif 指令用于终止#if,#ifdef,#ifndef和预处理指令。
3.宏替换:
宏定义中可以出现其他宏定义的符号,但是不能出现递归。
在定义宏时,经常会出现的两个运算符 # 和 ##
#:出现在宏定义中的#运算符,会将其后面参数转化为一个字符串。我们把这种用法的成为字符串化运算符。
##:常用于把多个参数连接在一起。
①在调用宏时,首先对参数进行检查,看看是否包含了任何由#define定义的符号。如果是它们首先被替换。
②替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替代。
③最后,再次对文本结果进行扫描,看看是否包含了任何由#define定义的符号。如果是就重复上述处理过程。
4.去注释:把源代码的注释部分全部删除。
2.编译
编译阶段会对程序进行语义语法纠错、将.c文件编译成汇编语言。生成的文件后缀为 .s
-S 从现在开始对文件进行编译,编译结束后停止操作。
命令为:gcc -S myfile.i -o myfile.s
同理,其中的选项-o和生成的文件myfile.s必须相邻。
注:汇编语言与机器语言一一对应,是高级语言转化为机器语言的“中间人”。
3.汇编
汇编阶段进行将汇编语言变成二进制机器语言,生成可重定位目标二进制文件bin.obj,不可执行,后缀为 .o
-c 从现在开始对文件进行编译,汇编结束后停止操作。
命令为:gcc -c myfile.s -o myfile.o
同理,其中的选项-o和生成的文件myfile.o必须相邻。
注:汇编阶段是对自己编写的代码转化成汇编语言后进行转换得到的目标二进制文件,还未与高级语言的库进行连接和转换,生成的目标文件是不可执行的。
4.链接
链接阶段将所有的目标文件和依赖的库文件进行汇总,得到最终的可执行程序。
与一次编译完是同一个命令,不需要额外的选项。
命令为:gcc myfile.o -o myfile
同理,其中的选项-o和生成的文件myfile必须相邻。
那么,为什么gcc能进行C语言代码的编译并生成可执行文件呢?
因为,Linux系统默认携带了语言级别的头文件和语言对应的库。
库分为两种——动态库(专门让编译器与用户的程序进行动态链接的)和静态库(专门让编译器与用户的程序进行静态链接的)。
静态库和静态链接:程序链接时如果是静态链接,则链接的库是静态库,链接的方式是通过 拷贝库文件中所需要的代码至二进制文件,链接成功后程序的执行不依 赖静态库,但多个程序执行拷贝相同的代码会带来空间的浪费。
动态库和动态链接:程序链接时如果是动态链接,则链接的库是动态库,链接的方法是拷贝 库文件中所需要代码的地址至二进制文件,链接成功后程序的执行依赖 动态库,若动态库被删除,则程序无法执行。
动态库和静态库的比较:动态库被链接时,代码的内容并没有被拷贝,而拷贝的是相关代码 的地址,较静态库而言节省空间,也避免了代码重复拷贝带来的不 必要空间浪费。Linux系统默认链接的是动态库。
动态库的名称默认格式:libxxxx.so
静态库的名称默认格式:libxxxxx.a
(lib是前缀,.so和.a是后缀,xxxxx是库的名字
对于编译生成的可执行文件,可以通过命令“ldd 文件名”来查看是文件编译时的链接是动态链接还是静态链接。
上图所示,test的链接方式是动态链接,链接的是动态库。
因为Linux系统默认链接的是动态库,想要进行静态链接,则需要增加一个-static的选项在命令的后面,整体的命令为gcc test.o -o test.static -static ,
(一般的云服务器,默认只有动态库,如果你想要进行静态链接,可以通过yum命令:yum install glibc-static libstdc++-static -y安装静态库 。)
三、实际操作实例
1.创建C程序文件test.c并用vim进行编写,保存后查看test.c的文件内容:
2.输入命令,进行文件的预处理,生成后缀为 .i 的文件test.i
3.输入命令,进行文件的编译操作,生成汇编文件test.s
4.输入命令,将汇编语言转换成二进制机器语言,生成二进制重定向文件test.o
5. 输入命令,将二进制文件和库文件进行合并,生成可执行文件test
6.用”ldd test“命令查看可执行文件test是否是动态链接
由上图可知,可执行文件test是动态链接的,链接的库是动态库(又称共享库)
7.通过命令gcc test.o -o test.static -static或者gcc test.c -o test.static -static来生成静态链接的可执行文件test.static
(注:上面对动态链接和静态链接的举例皆是借助该实例进行说明的)
四、总结
本文主要讲述了gcc编译器编译代码的基本过程,以及链接时链接的库文件的属性分类及对应的链接方法。gcc是Linux系统下的C语言编译器,可以执行我们编辑的C语言代码,但如果涉及到多文件(即项目文件需要多个.c文件)时,像上述的方法进行编译会很麻烦,那应该如何解决呢?下篇文章将会进行相关工具——make和Makefile的讲解,欢迎大家垂阅。
今天的文章linux gcc编译器_C++编译器[通俗易懂]分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/71413.html