gcc在开发初期的确是定位在一款C编译器,从其名字就可以推测出来:GNU C Compiler。然而经过十多年的发展,gcc的含义已经悄然改变,成为GNU Compiler Collection,同时支持C、C++、Objective C、Chill、Fortran和Java等语言。这里以几个实例介绍gcc编译器的用法。作为自由软件的旗舰项目,gcc的功能是如此强大,这里无法列举其每一个选项,有需要的话可以参考GNU gcc手册。
编译第一个C程序
假设我们已经有了一个C文件名为summary.c,其内容如下:
#include
int summary(int n);
int main()
{
int i,result;
result=0;
for(i=1;i<=100;i++)
{
result+=i;
}
printf("Summary[1-100]=%d\n",result);
printf("Summary[1-450]=%d\n",summary(450));
return 0;
}
int summary(int n)
{
int sum=0;
int i=0;
for(i=1;i<=n;i++)
{
sum+=i;
}
return sum;
}
要编译一个C语言程序,只要简单的使用gcc命令后跟一个C源文件作为参数。下面这条命令编译文件summary.c。
$ gcc summary.c
编译之后产生的可执行文件叫做a.out,位于当前目录下。下面执行这个程序
$ ./a.out
不过,看起来似乎没有人喜欢a.out这个默认的文件名。gcc提供了-o选项让用户指定可执行文件的文件名。下面这条命令将summary.c编译成可执行文件sum。
$ gcc -o sum summary.c
$ ./sum
同编译有关的选项
读者已经知道如何使用gcc生成可执行文件了:只需要1行命令,2个(或4个)单词。有点出乎意料的容易。是吗?然而在很多情况下,程序员需要的不只是一个可执行程序那么简单。一些场合需要目标代码,有些时候程序员又要得到汇编代码等,gcc很擅长满足这些需求,下表列出了和编译有关的若干选项。
和编译有关的选项
---------------------------------------------------------------------------------------------
选项 | 功能
---------------------------------------------------------------------------------------------
-c | 只激活预处理、编译和汇编,生成扩展名为.o的目标代码文件
-S | 只激活预处理和编译,生成扩展名为.s的汇编代码文件
-E | 只激活预处理,并将结果输出至标准输出
-g | 为调试程序(如gdb)生成相关信息
---------------------------------------------------------------------------------------------
-c选项在编写大型程序的时候是必须的。存在依赖关系的源代码文件总是要首先编译成目标代码,最后一起连接成可执行文件。当然,如果一个程序拥有超过3个源代码文件,那就应该考虑使用make工具了——介绍makefile的语法已经超出了本书的范围,有兴趣的读者可以参考Linux编程方面的书籍。一些C语言教程也会对Linux的makefile做了简要介绍,如Al Kelley和Ira Phol的A Book on C(中文版《C语言教程》,机械工业出版社)。
在使用-E选项的时候要格外小心,不要想当然地以为gcc会把结果输出到某个文件中。恰恰相反,gcc是在屏幕上(准确的说是标准输出)显示其处理结果的。只要程序中包含了标准库的头文件,那么预处理后的结果一定是很长的,应该使用重定向将其输出到一个文件中。
$ gcc -E summary.c > pre_sum
下面这个例子可以帮助C语言初学者理解他们错在哪里。
$ cat macro.c
/* macro.c */
#define SUB(X,Y) X*Y
int main()
{
int result;
result = SUB(2+3,4);
return 0;
}
$ gcc -E macro.c
...
int main()
{
int result;
result = 2+3*4;
return 0;
}
选项-g是为调试准备的。
优化选项
程序员总是希望自己的作品执行起来更为快速、高效。这除了取决于代码本身的质量,编译器也在其中发挥了不可小视的作用。同一条语句可以被翻译成不同的汇编代码,但是执行效率却大相径庭。有些编译器不够聪明,他们甚至不愿理会程序员在源代码中的“暗示”,因此只能生成效率低下的目标代码。gcc显然不在此列。除了足够“聪明”之外,gcc还提供了各种优化选项供程序员选择。为了得到经过特别优化的代码,最简单的方法是通过使用-Onum选项。
gcc提供了3个级别的优化选项,从低到高依次是-O1、-O2和-O3。理论上-O3可以生成执行效率最高的目标代码。然而,优化程度越高就意味着冒更大的风险。通常来说,-O2选项就可以满足绝大多数的优化需求,也足够安全。
事实上,-O1、-O2、-O3是对多个优化选项的“打包”。用户也可以手动指定使用哪些优化选项。gcc的优化选项通常都很长,以至于有时候看上去像是一堆随机字符序列,有兴趣的读者可以参考gcc的官方手册。
一个比较“激进”的优化方案是使用-march选项。gcc会为特定的CPU编译二进制代码,产生的代码只能在该型号的CPU上运行。例如:
$ gcc -O2 -march=pentium4 summary.c
上面这条命令在64位机器上会产生错误:
summary.c:1:错误:您选择的CPU不支持x86-64指令集
summary.c:1:错误:您选择的CPU不支持x86-64指令集
如果没有特殊需要,不建议使用-march选项。另外,一些软件在使用优化选项编译后会产生各种问题,例如Linux系统的基本C程序库glibc就不应该使用优化选项编译。
编译C++程序:g++
下面是一个名为hello.cpp的C++源文件的内容:
#include
using namespace std;
int main()
{
cout<<"Hello World !!"<
return 0;
}
gcc命令可以编译C++源文件,但不能自动和C++程序使用的库连接。因此通常使用g++命令来完成C++程序的编译和连接,该程序会自动调用gcc实现编译。
$ g++ -o hello hello.cpp
g++的选项和gcc基本一致。上面的例子编译C++文件hello.cpp,并把生成的可执行文件命名为hello。