熟悉编译器gcc/g++

本文说是为了熟悉gcc/g++编译器,除此之外,还希望读者能对源程序被执行起来的整个过程有更深刻的理解。

gcc和g++的用法差不多,本文就以gcc为例来讲解

一个源程序被执行起来首先要经过四个步骤:预编译、编译、汇编、链接。
预编译: 1)、宏替换与删除。将代码中展开所有的宏,并将所有的#define宏定义删除
               2)、文件包含。引入包含的头文件。
               3)、条件编译。选择编译#if  #else if #else #ifdef #endif 里边包含的内容,将不进行编译的内容删除。
               4)、去注释。删除所有的注释// 和/*  */
               5)、添加行号与文件名标识,以便调试用的行号信息以及编译错误或警告时能够显示行号
               6)、保留所有的#pragma预编译指令,因为编译器需要它们
 
使用gcc进行预编译添加选项 -E    对源文件进行预编译后停止编译,生成文件后缀为 .i
如果想要对一个源程序hello.c只进行预编译,可以使用命令 gcc -E  hello.c  -o  hello.i  , 生成的文件为 hello.i  

编写hello.c源文件
#include <stdio.h>
#if 0
int mian()
{
    printf("this is guaiguai\n");
}
#else
#define COUNT 3
//主函数
int main()
{
    int count = COUNT;
    while(count--)
    {
        printf("hello world\n");
    }
    return 0;
}
#endif
然后使用命令 gcc -E hello.c -o hello.i 进行预编译,然后使用命令 cat hello.i 查看hello.i文件里边的内容,将源文件与hello.i里边的内容作对比。由于将头文件的内容都引入了,所以 hello.i里边的内容非常非常多,在这里只展示了头文件中极少极少的一部分


编译(生成汇编) :1)、词法分析
                                  2)、语法分析
                                  3)、语义分析
                                  4)、优化
                                  5)、将源代码翻译成汇编语言
对源文件进行编译使用gcc 添加选项 -s , 编译完成后停止,生成后缀为  .s  的文件。
如对hello.c文件进行编译,使用命令 gcc -s  hello.c -o  hello.o

由于此时的hello.o文件里边的内容已经不是我们能看懂的了,就不打开看了

汇编(生成机器可识别的代码) :汇编阶段是将生成的.s 文件转成目标文件 后缀为 .o

链接(生成可执行文件或库文件): 在成功编译之后,就进入了链接阶段。有时候一个工程比较庞大,往往把它分成几个源文件来编写,最后才将这些文件生成的目标文件和库链接在一块,生成最终的可执行文件。 (举的例子里就一个文件)
使用命令gcc hell.o -o hello  就生成了一个可执行文件hello 。使用 ./ hello 就可以运行可执行程序hello了。

总结
用到的gcc选项可能不太好记,其实只要记住它的顺序与键盘左上角的Esc键一致就是了。

除了以上用到的那些除外,gcc还有很多其他的常用的选项,在这里简单总结一下。
-E  预处理
-s  编译
-c  汇编
-o  文件输出到跟在-o 后边的文件
-g  生成调试信息,如果需要使用gdb调试程序的话,一定要加此选项
-static  此选项对生成的文件采用静态链接
-share 加此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库
编译器的优化选项有4个级别,从-O0 到-O3 ,其中,默认为-O1。
-O0
-O1
-O2
-O3  优化级别最高
-w    不生成任何警告信息。
-Wall 生成所有警告信息 -----默认情况就是这样的。

在要编译的文件后边加
-L 指定库路径
-l 指定库名

PS:我们在编写C语言代码的时候,可能已经习惯了用C99的标准去编写,但是gcc编译器默认以c89的标准去编译我们的程序。如果我们希望它以C99的标准去编译的话,在编译的时候,就需要加上一句 -std=c99
上边提到了静态库和动态库,在此简单介绍一下什么是
静态库和动态库
静态库(.a) :程序在编译链接的时候把库的代码链接到可执行文件中。程序运行时将不再需要静态库,因为它的代码已经成为可执行文件的一部分了。所以,如果一个程序使用静态库的话,那么它的可执行文件是很大的。
动态库(.so): 程序在运行的时候才会去链接动态库,多个程序共享使用库的代码。
一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个代码器
在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为 动态链接(dynamic linking)。
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。
操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。

最后分享给大家一片非常棒的博文分享给大家。原文出自博客园昵称为可可西的作者 https://kekec.cnblogs.com/p/3238741.html


猜你喜欢

转载自blog.csdn.net/guaiguaihenguai/article/details/78689723