Linux C ————15、使用GCC

gcc编译器功能强大,包括警告提示功能、代码优化功能、链接库、使用管道加速等,下面通过一个个具体的实例来一一介绍这些功能。

GCC编译初步

如前面所述,gcc的编译过程分为预处理、编译、汇编、链接4个阶段。从功能上分,预处理、编译、汇编是3个不同的阶段,但gcc在实际操作上,可以吧这3个步骤合并为一个步骤来执行。下面通过简单的Hello world的例子来讲解gcc的工作原理。

首先用vi编辑器键入一下代码并保存为hello.c


然后输入下面的命令编译和运行这段程序:


运行上述命令过后,我们可以发现编译器自动创建了一个a.out的输出文件,而“./”表示执行当前目录下的可执行程序或脚本程序。当然,用户可以使用gcc的选项“-o”来改变编译后的文件名,如使用下面的命令,将输出文件命名为“hello”,执行hello文件之后可以得到相同的结果


现在我们回到编译过程中,从程序员的角度来看,只需要简单的一条gcc命令就可以了,但从编译器的角度来看,却需要完成一系列非常繁杂的工作。

  • 首先,gcc需要调用预处理程序cpp,由它复杂展开在源文件中定义的宏,并向其中插入“#include”语句所包含的内容
  • 接着,gcc会调用ccl和as将处理后的源代码编译成目标代码;
  • 最后gcc,会调用链接程序ld,把生成的目标代码链接成一个可执行程序。

为了更好的理解gcc的处理过程,可以把以上编译过程分成几个步骤单独进行,并观察每一步之后的结果:

(1)预处理。在预处理阶段,gcc吧预处理命令扫描处理完毕,输入C语言的源文件,通常为*.c,他们通常带有.h之类的包含文件。这个阶段主要处理源文件中的#ifdef、#include、#define等预处理命令。该阶段会生成一个中间文件*.i,但实际工作中通常不会专门生成这类文件,因为基本上都用不到,若非要生成这种文件,可以使用-E参数让gcc在预处理结束后停止编译过程。



此时会发现头文件中的stdio.h的内容已经被插入到文件中去了,而其他应当被预处理的宏定义也都做了相应的处理

(2)编译阶段:在编译阶段,gcc把预处理后的结果编译成汇编或目标模块。输入的是中间文件*。i在编译后生产汇编语言文件*.s。这个阶段对应的gcc命令如下:


(3)汇编:在汇编阶段,编译器会把编译出来的结果汇编成具体CPU上的目标代码模块。输入汇编文件*.s,输出机器语言*.o。这个阶段可以通过是哟-c参数来实现


(4)链接:在链接阶段吧多个目标代码模块链接生成一个大的目标模块。输入机器代码文件*.o(与其他的既期待吗文件和库文件),汇集成一个可执行的二进制代码文件,这一步骤可以通过以下代码实现:

运行hello


警告显示显示功能

gcc包含完整的出错检查和警告提示功能,它们可以帮助LInux程序员写出更加专业和优美的代码。

-pedantic编译选项并不能保证被编译的程序与ANSI/ISO C标准的完全兼容,它只能用来帮助Linux程序员离这个目标越来越近,换句话说,-pedantic选项能够帮助程序员发现一些不符合ANSI/ISO C标准的代码,但不是全部。事实上只有ANSI/ISOC语言标准中要求进行编译器诊断的哪些情况,才有可能被gcc发现并提出警告。

除-pedantic之外,gcc还有一些其他编译选项也能够产生有用的警告信息。这些选项大多数都是有-W开头,其中最有价值的是-Wall使用它能够使gcc产生尽可能多的警告信息。

gcc给出的警告信息虽然从严格意义上来说不能算错误,但是却很可能成为错误的栖身之所。一个优秀的Linux程序员应该尽量避免产生警告信息,是自己的代码始终保持简洁、优美和健壮的特性。

优化gcc

代码的优化功能是线代C编译器一个最令人心动的特性,作为Linux平台下的标准C编译器,gcc拥有强大并且可配置的优化器,从而能够对程序进行优化处理。

代码优化指的是编译器通过分析源代码,找出其中尚未达到最优的部分,然后对其重新组合,目的是改善程序的执行性能。gcc提供的代码优化功能非常强大,它通过编译选项-On来控制优化代码的生成,其中n是一个代表优化级别的整数。对于不同版本的gcc来说,n的取值范围以及对应的优化效果可能并不相同,比较典型的范围是从0变到2或3.

编译时使用选项-O可以告诉gcc同时减小代码的长度和执行时间,其效果等价于-O1。在这一级别上能够进行优化类型虽然取决于目标处理器,但一般都会包括线程跳转延迟退栈两种优化。

-O2选项告诉gcc除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,比如处理器指令调度等。

选项-O3告诉gcc除了完成所有-O2的优化之外,同时还包括循环展开和其他一些与处理器特性相关的优化工作。通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。许多Linux程序员都比较喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。

同时编译多个源程序

在采用模块化设计思想进行软件开发时,通常整程序是由多个源文件组成的。也就相应的形成了多个编译单元,使用gcc能够很好的管理这些编译单元。假设有一个由fool1.c\foo2.c\foo3.c三个源文件组成的程序,为了对他们进行编译,并最终生成一个可执行文件,可以使用下面这条命令:

gcc  foo1.c foo2.c foo3. c -o foo

管道

Linux提供了一种高效的通信方式——管道(pipe).管道的实质是进程间的通信方式,在这里简单地说,它可以用来同时连接两个程序(进程),其中一个程序的输出程序将被直接作为另外一个程序的输入,这样就可以避免使用临时文件,但编译时却需要消耗更多的内存。

在编译过程中使用管道是由gcc的pipe选项决定的。下面这条命令就是借助gcc的管道功能来提高编译速度的:

gcc  -pipe  -Wall foo.c  -o foo

调试选项

在默认情况下,gcc在编译时不会将调试符号插入到生成的二进制代码中,因为这样会增加可执行文件的大小。如果需要在编译时生成调试符号信息,可以使用gcc的-g选项或者-ggdb选项。

gcc在产生调试符号时,同样采用了分级的思路,开发人员可以通过在-g选项后附加数字1,2,3来指定在代码中加入调试信息的多少。默认级别是2(-g2),此时产生的调试信息包括扩展的符号表、行号、局部或外部变量信息。级别3(-g3)包含级别2中的所有调试信息,以及源代码和宏。


加入调试选项比不加入调试选项生成的文件要大。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FLy_鹏程万里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值