GCC简介

一、GCC简介

通常所说的GCC是GNU CompilerCollection的简称,除了编译程序之外,它还含其他相关工具,所以它能把易于人类使用的高级语言编写的源代码构建成计算机能够直接执行的二进制代码。GCC是Linux平台下最常用的编译程序,它是Linux平台编译器的事实标准。同时,在Linux平台下的嵌入式开发领域,GCC也是用得最普遍的一种编译器。GCC之所以被广泛采用,是因为它能支持各种不同的目标体系结构。例如,它既支持基于宿主的开发(简单讲就是要为某平台编译程序,就在该平台上编译),也支持交叉编译(即在A平台上编译的程序是供平台B使用的)。目前,GCC支持的体系结构有四十余种,常见的有X86系列、Arm、 PowerPC等。同时,GCC还能运行在不同的操作系统上,如Linux、Solaris、Windows等。

除了上面讲的之外,GCC除了支持C语言外,还支持多种其他语言,例如C++、Ada、Java、Objective-C、FORTRAN、Pascal等。

二、程序的编译过程

对于GUN编译器来说,程序的编译要经历预处理、编译、汇编、连接四个阶段。

从功能上分,预处理、编译、汇编是三个不同的阶段,但GCC的实际操作上,它可以把这三个步骤合并为一个步骤来执行。下面我们以C语言为例来谈一下不同阶段的输入和输出情况。

在预处理阶段,输入的是C语言的源文件, 通常为*.c。它们通常带有.h之类头文件的包含文件。这个阶段主要处理源文件中的#ifdef、 #include和#define命令。>该阶段会生成一个中间文件*.i,但实际工作中通常不用专门生成这种文件,因为基本上用不到;若非要生成这种文件 不可,可以利用下面的示例命令

gcc -E test.c -o test.i

在编译阶段,输入的是中间文件*.i,编译后生成汇编语言文件*.s 。这个阶段对应的GCC命令如下所示:

gcc -S test.i -o test.s

在汇编阶段,将输入的汇编文件*.s转换成机器语言*.o。这个阶段对应的GCC命令如下所示:

gcc -c test.s -o test.o

最后,在连接阶段将输入的机器代码文件*.o(与其它的机器代码文件和库文件)汇集成一个可执行的二进制代码文件。这一步骤,可以利用下面的示例命令完成:

gcc test.o -o test

上面介绍了GCC编译过程的四个阶段以及相应的命令。下面我们进一步介绍常用的GCC的模式。

三、GCC常用模式

这里介绍GCC追常用的两种模式:编译模式和编译连接模式。下面以一个例子来说明各种模式的使用方法。为简单起见,假设我们全部的源代码都在一个文件test.c>中,要想把这个源文件直接编译成可执行程序,可以使用以下命令:

$ gcc -o test.c

这里test.c是源文件,生成的可执行代码存放在一个名为test的文件中(该文件是机器代码并且可执行)。-o 是生成可执行文件的输出选项。如果我们只想让源文>件生成目标文件(给文件虽然也是机器代码但不可执行),可以使用标记-c ,详细命令如下所示:

$ gcc -c test.c

默认情况下,生成的目标文件被命名为test.o,但我们也可以为输出文件指定名称,如下所示:

$ gcc -c test.c -o mytest.o

上面这条命令将编译后的目标文件命名为mytest.o,而不是默认的test.o。

迄今为止,我们谈论的程序仅涉及到一个源文件;现实中,一个程序的源代码通常包含在多个源文件之中,这该怎么办?没关系,即使这样,用GCC处理起来也并不>复杂,见下例:

$ gcc -o test first.c second.c third.c

该命令将同时编译三个源文件,即first.c、second.c和 third.c,然后将它们连接成一个可执行程序,名为test。

需要注意的是,要生成可执行程序时,一个程序无论有有一个源文件还是多个源文件,所有被编译和连接的源文件中必须有且仅有一个main函数,因为main函数是该程序的入口点(换句话说,当系统 调用该程序时,首先将控制权授予程序的main函数)。但如果仅仅是把源文件编译成目标文件的时候,因为不会进行连接,所以main函数不是必需的。

四、常用选项

许多情况下,头文件和源文件会单独存放在不同的目录中。例如,假设存放源文件的子目录名为./src,而包含文件则放在层次的其他目录下,如./inc。当我们在./src 目录下进行编译工作时,如何告诉GCC到哪里找头文件呢?方法如下所示:

$ gcc test.c –I../inc -o test

上面的命令告诉GCC包含文件存放在./inc 目录下,在当前目录的上一级。如果在编译时需要的包含文件存放在多个目录下,可以使用多个-I 来指定各个目录:

$ gcc test.c –I../inc –I../../inc2 -o test

这里指出了另一个包含子目录inc2,较之前目录它还要在再上两级才能找到。 另外,我们还可以在编译命令行中定义符号常量。为此,我们可以简单的在命令行中使用-D选项即可,如下例所示:

$ gcc -DTEST_CONFIGURATION test.c -o test

上面的命令与在源文件中加入下列命令是等效的:

#define TEST_CONFIGURATION

在编译命令行中定义符号常量的好处是,不必修改源文件就能改变由符号常量控制的行为。

五、警告功能

当GCC在编译过程中检查出错误的话,它就会中止编译;但检测到警告时却能继续编译生成可执行程序,因为警告只是针对程序结构的诊断信息,它不能说明程序一定有错误,而是存在风险,或者可能存在 错误。虽然GCC提供了非常丰富的警告,但前提是你已经启用了它们,否则它不会报告这些检测到的警告。 在众多的警告选项之中,最常用的就是-Wall选项。该选项能发现程序中一系列的常见错误警告,该选项用法举例如下:

$ gcc -Wall test.c -o test

该选项相当于同时使用了下列所有的选项:

需要注意的是,各警告选项既然能使之生效,当然也能使之关闭。比如假设我们想要使用-Wall来启用个选项,同时又要关闭unused警告,利益通过下面的命令来达到目的:

$ gcc -Wall -Wno-unused test.c -o test

下面是使用-Wall选项的时候没有生效的一些警告项:

上面是使用-Wall选项时没有生效,但又比较常用的一些警告选项。本文中要介绍的最后一个常用警告选项是-Werror。使用该选项后,GCC发现可疑之处时不会简单的发出警告就算完事,而是将警告作为一个错误而中断编译过程。该选项在希望得到高质量代码时非常有用。

六、GCC与G++

gcc开始时候的名字是gnu c compiler, 就是说设计的初衷是用来编译C语言的。 后来,不断的拓展发展成了 gnu compiler collection. 如果你用gcc编译过fortran代码的话,就会对后者理解的比较深刻了。现在的gcc可以看做是gnu支持的语言编译器的前端。g++的设计目标是用来编译C++程序代码的,如期名字所暗示的那样。因此,g++是一个c++ compiler,gcc是 compiler collection. 所以,可以推知g++的功能只是gcc的一个子集。 gcc可以用来编译.cpp为后缀的c++程序源文件,同样g++也可以。你可能以为使用gcc编译的时候,会调用g++。然而,并非如此!!!g++诞生的比gcc晚,刚诞生的g++事实上是用脚本语言写的,其中将一系列的命令行参数传给了gcc,所以应该说g++的内部调用了gcc。旧版本的g++中,g++的实现脚本是用bash写的。虽然现在的g++使用二进制可执行文件写的,但是内部原理还是一样的。

gcc和g++的具体区别有以下几点:

对于.cpp为后缀的C++文件,使用gcc编译或者g++编译效果差不多一样的,但是连接的时候不同,g++会在链接的时候自动使用libstdc++,而gcc不会。

gcc -o md5test md5.o md5.test.o -lstdc++

对于.c为后缀的源文件,gcc默认使用c编译器去编译,而g++默认调用的是c++的编译器。

-- EOF --
发表于: 2015-04-19 12:55
标签: C++ GCC