让GCC帮助你更好的工作

上面我们简单介绍了GCC的常用命令行选项,其实GCC的功能比上面提到的那些要丰富得多,GCC对代码的警告、优化、调试等方面提供了丰富的支持,下面我们就从一些例子来看看GCC提供的这些功能。

1.对问题代码提出警告

GCC对程序代码提供了完整的检查功能,由于C/C++语言本身的特点,很多错误都是程序员无意间犯下的,例如使用了未定义的变量、在bool表达式中使用了=而不是==等等问题,利用GCC提供的代码检查功能,我们可以让编译器为我们找到这些问题,避免运行时发生灾难。

首先,我们来看一个“问题代码”

/* test_warning.c We use this file to check the warning facilities provided by GCC*/ #include #include

void main() { /* main should return int*/

int a, b; long long l = 2.2; /* long long type is GNU extension, not standard ANSI / ISO type*/

miss_decl(); /* We call an undeclared function*/

if (a = 0) /* May be we want == here instead of =*/

printf (“a really equals to 0?\n”); if (b != 0)      /* We used uninitialized variables*/ /* %d and “We should put b here” don‘t match*/ printf(“We make a mistake again! b = %d\n”, “We should put b here”);

};

void miss_decl() {

/* /* This type of annotation is prohibited*/

printf(“We should put the declaration before it‘s been used!\n”);

}

上面这些代码故意制造了很多编程中出现的常见问题,接下来,我们就用这段代码来检测一下GCC提供的各种常用的警告设施。

首先,我们不使用任何警告设施编译上面的程序gcc test_warning.c –o test_warning默认情况下,GCC会给出输出,其中GCC识别出了main函数不标准warning)以及使用了未声明的函数error)两个问题,但是其他的GCC并未察觉。

1.利用-pedantic找出不符合ANSI / ISO标准的代码

执行下面的命令:gcc –pedantic test_warning.c –o test_warning可以看到,这次GCC以警告的形式报告了代码中long long的使用,但是要说明的是我们并不能依赖这个选项来保证我们的代码完全符合ANSI / ISO标准,因为该选项只报告ANSI C要求编译器进行检察的内容。另外,你还可以使用-pedantic-errors让GCC把所有的警告都变成错误。

2. 利用-Wformat检查printf中的参数不匹配问题执行下面的命令:gcc –Wformat test_warning.c –o test_warning

3. 利用-WComment找出注释中的错误执行下面的命令:gcc –WComment test_warning.c –o test_warning

4. 利用-Wparentheses查找bool表达式中的=错误执行下面的命令:gcc –Wparentheses test_warning.c –o test_warning

5. 用-Wuninitialized查找未初始化变量的使用执行下面的命令:gcc –O –Wuninitialized test_warning.c –o test_warning值得说明的是,在使用这个选项的时候,一定要配合上-O(后面我们会提到)选项

6. 利用-Wimplicit-function-declaration / -Werror-implicit-function-declaration检查未声明函数的使用执行下面的命令:gcc -Wimplicit-function-declaration test_warning.c –o test_warning另外-Werror-implicit-function-declaration和-Wimplicit-function-declaration作用是类似的,只是如果你使用了未声明的函数,前者会把它认为是一个错误。

7. 如果你只是想对你的代码进行全面的检查,你大可不必把上面的选项一并列出来,GCC提供了-Wall选项,含义就是列出所有代码中的警告执行下面的命令:gcc –Wall test_warning.c –o test_warning 8. 如果你想走另一个极端,也就是不想让gcc输出任何警告,那么使用-w选项,该选项禁止所有的警告执行下面的命令:gcc –w test_warning.c –o test_warnin

<输出结果>

对于上面所有的选项,你都可以把它们和-Werror选项一起使用,这样就可以把所有的警告都变成错误。另外,如果你只是想对代码进行检查而并不执行编译的话,可使用-fsyntax-only选项,像下面的命令这样gcc –fsyntax-only test_warning.c基本上来说,我们常用的一些警告选项就是这些,而其中-Wall更是我们极为常用的功能。

2. 优化选项这一部分的内容可以分成两部分,一部分是让编译器对代码进行分析

后,进行的代码优化,另一部分是我们可以为编译器制定一些关于硬件的信息,让他生成对硬件结合的更好的代码,而我们之所以要用源代码来编译程序,很多情况下,是出于这方面的原因。

首先来看代码优化,从代码的整体优化上,GCC提供了下面的选项

-O–O1

这两个选项的含义是一样的,GCC将执行减少代码尺寸和执行时间的优化,对于那些会严重影响编译时间的优化选项,这个级别的优化并不会执行。

-O2

在这一级别GCC将会提供所有支持的优化,但这其中并不包括以空间换时间的优化手段,例如编译器不会使用循环展开和函数内联。和-O相比,该选项进一步加快了编译时间和生成代码的性能。

-O3

除了-O2提供的优化选项外,还指定了-finline-functions,-funswitch-loops和-fgcse-afer-reload选项,目的只有一个就是全力执行代码优化。

-Os

这个选项是专门用来优化代码尺寸的,-Os打开了所有-O2级别中不会显著增长代码尺寸的优化选项

-O0

该选项代表不执行优化

在这里要说明的是,尽管GCC提供了1~3和s这4个整体优化选项,但从实际的优化效果上来看,往往O3优化出来的程序的效率并不是最高的,而大部分情况下我们都在使用-O2,如果你希望获得最高的效率利益,那么不妨这4个选项都试试。另外,其实这些选项只不过是GCC提供的很多单方面优化的一个组合,如果你想了解更为具体的优化内容,可以去查看GCC手册,出于篇幅限制,这里不细谈了。最后要记住的一点是,如果你的程序是用于高精度数值计算的,那么记住不要使用上面任何的优化选项。

下面来看基于硬件优化,由于这部分和计算机硬件相关,这里仅用Intel的CPU做一些说明:对于所有为Intel和AMD x86-64提供的优化选项都是用m开头的,下面写一些常用的选项:

-march

该选项用来指定CPU的类型,常用的有i386 \ i486 \ i586 \ pentium-mmx \ i686 \ pentium2 \ pentium3 \ pentium-m \ pentium4 \ prescott \ k6 \ athlon \ athlon-4 \ k8等等,读者可以根据自己的情况进行指定。

-mfpmath

该选项用于指定浮点运算单元的类型。包括

387

使用标准的数学协处理器

sse

使用SSE指令集提供的标量浮点运算。在Pentium3 \ Athlon-4以及更新的芯片上支持这个特性。另外,在pentium4以及AMD x86-64处理器上,SSE2还可以进行双精度浮点计算。

sse,387混合使用387数学协处理器和SSE指令集,该选项可以充分的利用CPU的浮点寄存器和xmm寄存器,但是该选项还处在试验阶段。

-malign-double

该选项使得GCC把double \ long double \ long long类型的变量在4字节或2字节地址上对齐,在Pentium级的CPU上,这会使得代码的执行速度更快,当然带来的代价是需要更多的内存来执行程序。-mmmx –msse –msse2 –msse3 –m3dnow这些选项用来启动内置函数直接使用这些处理器扩展指令的功能。在编译3D或多媒体程序的时候,使用他们是非常有效的。

3. 对调试的支持当程序出错的时候,我们可以在Visual Studio中轻松的进行调试,而在Linux中,一旦出现Segmentation Fault,似乎我们除了用眼睛去看代码就没有更好的选择了,其实情况不然,用GCC向程序加入一些适当的调试信息,我们可以利用GDB去调试程序。在这里,我们介绍最为常用的-g和-ggdb选项。

先来看-g。该选项可以利用操作系统的“原生格式native format)”生成调试信息。GDB可以直接利用这个信息。尽管我们可以把-O和-g放在一起使用,但是,这种做法是极为不推荐的。

如果你想用GDB来调试程序,那么你可以使用-ggdb来让GCC为GDB生成更为丰富的调试信息,但是,此时你就不能用其他的调试器来进行调试了。

最后要说明的是,上面这两个选项都可以接受一个输出调试信息的级别,默认的级别是2。如果你指定1级-g1),那么GCC会生成最少的调试信息,这包括函数和全局变量的描述信息,但是对于局部变量和行号等信息,在这个级别是不会输出的。另外一个级别是3级-g3),在这一级别上,GCC会为程序中的所有宏定义和符号生成调试信息。

小结

通过这篇文章,希望能过对想学习Linux开发中用到的一些基本的技术和知识有一个了解,并且能够自己动手开始做些试验性的工作,其实,这里还有很多问题没有谈到,例如利用GDB进行调试、利用make管理工程、利用autoconf为程序生成配置脚本、利用CVS管理程序源文件等等,这些问题有待在今后的文章中和读者一起交流。


相关内容