gcc教程.docx

上传人:b****6 文档编号:3646260 上传时间:2022-11-24 格式:DOCX 页数:12 大小:27.23KB
下载 相关 举报
gcc教程.docx_第1页
第1页 / 共12页
gcc教程.docx_第2页
第2页 / 共12页
gcc教程.docx_第3页
第3页 / 共12页
gcc教程.docx_第4页
第4页 / 共12页
gcc教程.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

gcc教程.docx

《gcc教程.docx》由会员分享,可在线阅读,更多相关《gcc教程.docx(12页珍藏版)》请在冰豆网上搜索。

gcc教程.docx

gcc教程

一:

不经意间,GCC已发展到了4.3的版本,尽管在软件开发社区之外乏人闻问,但因为GCC在几乎所有开源软件和自由软件中都会用到,因此它的编译性能的涨落会直接影响到Linux、Firefox乃至于OpenOffice.org和Apache等几千个项目的开发。

因此,把GCC摆在开源软件的核心地位是一点也不为过。

另一方面,GCC4.3的出现,正在牵引着广大程序员们的心。

如果我们非要用一个词来说明GCC与程序员之间的关系,那无疑是"心随心动"。

历史篇

作为自由软件的旗舰项目,RichardStallman在十多年前刚开始写作GCC的时候,还只是把它当作仅仅一个C程序语言的编译器;GCC的意思也只是GNUCCompiler而已。

经过了这么多年的发展,GCC已经不仅仅能支持C语言;它现在还支持Ada语言、C++语言、Java语言、ObjectiveC语言、Pascal语言、COBOL语言,以及支持函数式编程和逻辑编程的Mercury语言,等等。

而GCC也不再单只是GNUC语言编译器的意思了,而是变成了GNUCompilerCollection也即是GNU编译器家族的意思了。

另一方面,说到GCC对于各种硬件平台的支持,概括起来就是一句话:

无所不在。

几乎所有有点实际用途的硬件平台,甚至包括有些不那么有实际用途的硬件平台。

Gcc简介

Linux系统下的gcc(GNUCCompiler)是GNU推出的功能强大、性能优越的多平台编译器,是GNU的代表作品之一。

Gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%。

官方网站:

http:

//gcc.gnu.org/

gcc是linux的唯一编译器,没有gcc就没有linux,gcc的重要性就不可言喻啦。

居然这么重要,那就很值得我们来好好研究下啦。

好啦,开始我们的gcc之旅吧!

首先消除gcc和g++误区吧。

gcc和g++都是GNU(组织)的一个编译器。

误区一:

gcc只能编译c代码,g++只能编译c++代码

两者都可以,但是请注意:

1.后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序;后缀为.cpp的,两者都会认为是c++程序,注意,虽然c++是c的超集,但是两者对语法的要求是有区别的,例如:

#include

intmain(intargc,char*argv[]){

if(argv==0)return;

printString(argv);

return;

}

intprintString(char*string){

sprintf(string,"Thisisatest.\n");

}

如果按照C的语法规则,OK,没问题,但是,一旦把后缀改为cpp,立刻报三个错:

“printString未定义”;

“cannotconvert`char**'to`char*”;

”return-statementwithnovalue“;

分别对应前面红色标注的部分。

可见C++的语法规则更加严谨一些。

2.编译阶段,g++会调用gcc,对于c++代码,两者是等价的,但是因为gcc命令不能自动和C++程序使用的库联接,所以通常用g++来完成链接,为了统一起见,干脆编译/链接统统用g++了,这就给人一种错觉,好像cpp程序只能用g++似的。

误区二:

gcc不会定义__cplusplus宏,而g++会

实际上,这个宏只是标志着编译器将会把代码按C还是C++语法来解释,如上所述,如果后缀为.c,并且采用gcc编译器,则该宏就是未定义的,否则,就是已定义。

误区三:

编译只能用gcc,链接只能用g++

严格来说,这句话不算错误,但是它混淆了概念,应该这样说:

编译可以用gcc/g++,而链接可以用g++或者gcc-lstdc++。

因为gcc命令不能自动和C++程序使用的库联接,所以通常使用g++来完成联接。

但在编译阶段,g++会自动调用gcc,二者等价。

误区四:

extern"C"与gcc/g++有关系

实际上并无关系,无论是gcc还是g++,用extern"c"时,都是以C的命名方式来为symbol命名,否则,都以c++方式命名。

试验如下:

me.h:

extern"C"voidCppPrintf(void);

me.cpp:

#include

#include"me.h"

usingnamespacestd;

voidCppPrintf(void)

{

cout<<"Hello\n";

}

test.cpp:

#include

#include

#include"me.h"

intmain(void)

{

CppPrintf();

return0;

}

1.先给me.h加上extern"C",看用gcc和g++命名有什么不同

[root@rootG++]#g++-Sme.cpp

[root@rootG++]#lessme.s

.globl_Z9CppPrintfv//注意此函数的命名

.typeCppPrintf,@function

[root@rootGCC]#gcc-Sme.cpp

[root@rootGCC]#lessme.s

.globl_Z9CppPrintfv//注意此函数的命名

.typeCppPrintf,@function

完全相同!

2.去掉me.h中extern"C",看用gcc和g++命名有什么不同

[root@rootGCC]#gcc-Sme.cpp

[root@rootGCC]#lessme.s

.globl_Z9CppPrintfv//注意此函数的命名

.type_Z9CppPrintfv,@function

[root@rootG++]#g++-Sme.cpp

[root@rootG++]#lessme.s

.globl_Z9CppPrintfv//注意此函数的命名

.type_Z9CppPrintfv,@function

完全相同!

【结论】完全相同,可见extern"C"与采用gcc/g++并无关系,以上的试验还间接的印证了前面的说法:

在编译阶段,g++是调用gcc的。

二:

今天,我们继续gcc之旅吧。

上节我们讲了些gcc的历史发展什么的,还有就是gcc与g++的区别。

今天我们就从整体上对gcc编译过程有个细致的了解,也好明白他的工作原理,好为以后深入学习研究打下个基础。

gcc的编译流程分为四个步骤,分别为:

·预处理(Pre-Processing)

·编译(Compiling)

·汇编(Assembling)

·链接(Linking)

以hello.c为例子,在这四个步骤中可以设置选项分别生成hello.i,hello.s,hello.o以及最终的hello文件:

hello.c:

最初的源代码文件;

hello.i:

经过编译预处理的源代码;

hello.s:

汇编处理后的汇编代码;

hello.o:

编译后的目标文件,即含有最终编译出的机器码,但它里面所引用的其他文件中函数的内存位置尚未定义。

hello/a.out:

最终的可执行文件

(还有.a(静态库文件),.so(动态库文件),.s(汇编源文件)留待以后讨论)

下面就具体来查看一下gcc是如何完成四个步骤的。

hello.c源代码

#include

intmain()

{

printf("HelloWorld!

\n");

return0;

}

(1)预处理阶段

在该阶段,编译器将上述代码中的stdio.h编译进来,并且用户可以使用gcc的选项”-E”进行查看,该选项的作用是让gcc在预处理结束后停止编译过程。

《深入理解计算机系统》中是这么说的:

预处理器(cpp)根据以字符#开头的命令(directives),修改原始的C程序。

如hello.c中#include指令告诉预处理器读系统头文件stdio.h的内容,并把它直接插入到程序文本中去。

结果就得到另外一个C程序,通常是以.i作为文件扩展名的。

注意:

Gcc指令的一般格式为:

Gcc[选项]要编译的文件[选项][目标文件]

其中,目标文件可缺省,Gcc默认生成可执行的文件名为:

编译文件.out

[gan@localhostgcc]#gcc–Ehello.c–ohello.i

选项”-o”是指目标文件,”.i”文件为已经过预处理的C原始程序。

以下列出了hello.i文件的部分内容:

typedefint(*__gconv_trans_fct)(struct__gconv_step*,

struct__gconv_step_data*,void*,

__constunsignedchar*,

__constunsignedchar**,

__constunsignedchar*,unsignedchar**,

size_t*);

#2"hello.c"2

intmain()

{

printf("HelloWorld!

\n");

return0;

}

由此可见,gcc确实进行了预处理,它把”stdio.h”的内容插入到hello.i文件中。

(2)编译阶段

接下来进行的是编译阶段,在这个阶段中,Gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,Gcc把代码翻译成汇编语言。

用户可以使用”-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

汇编语言是非常有用的,它为不同高级语言不同编译器提供了通用的语言。

如:

C编译器和Fortran编译器产生的输出文件用的都是一样的汇编语言。

[gan@localhostgcc]#gcc–Shello.i–ohello.s

以下列出了hello.s的内容,可见Gcc已经将其转化为汇编了,感兴趣的读者可以分析一下这一行简单的C语言小程序是如何用汇编代码实现的。

.file"hello.c"

.section.rodata

.align4

.LC0:

.string"HelloWorld!

"

.text

.globlmain

.typemain,@function

main:

pushl%ebp

movl%esp,%ebp

subl$8,%esp

andl$-16,%esp

movl$0,%eax

addl$15,%eax

addl$15,%eax

shrl$4,%eax

sall$4,%eax

subl%eax,%esp

subl$12,%esp

pushl$.LC0

callputs

addl$16,%esp

movl$0,%eax

leave

ret

.sizemain,.-main

.ident"GCC:

(GNU)4.0.020050519(RedHat4.0.0-8)"

.section.note.GNU-stack,"",@progbits

(3)汇编阶段

汇编阶段是把编译阶段生成的”.s”文件转成目标文件,读者在此可使用选项”-c”就可看到汇编代码已转化为”.o”的二进制目标代码了。

如下所示:

[gan@localhostgcc]#gcc–chello.s–ohello.o

(4)链接阶段

在成功编译之后,就进入了链接阶段。

在这里涉及到一个重要的概念:

函数库。

在这个源程序中并没有定义”printf”的函数实现,且在预编译中包含进的”stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现”printf”函数的呢?

最后的答案是:

系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径”/usr/lib”下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数”printf”了,而这也就是链接的作用。

函数库一般分为静态库和动态库两种。

静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。

其后缀名一般为”.a”。

动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。

动态库一般后缀名为”.so”,如前面所述的libc.so.6就是动态库。

gcc在编译时默认使用动态库。

(Linux下动态库文件的扩展名为".so"(SharedObject)。

按照约定,所有动态库文件名的形式是libname.so(可能在名字中加入版本号)。

这样,线程函数库被称作libthread.so。

静态库的文件名形式是libname.a。

共享archive的文件名形式是libname.sa。

共享archive只是一种过渡形式,帮助人们从静态库转变到动态库。

完成了链接之后,gcc就可以生成可执行文件,如下所示。

[gan@localhostgcc]#gcchello.o–ohello

运行该可执行文件,出现正确的结果如下。

[root@localhostGcc]#./hello

HelloWorld!

三:

这一节,我们来关注下gcc的常用参数,有机会也好多加练习啦。

首先来看看我们gcc的版本吧,gcc--version这个命令就会显示gcc的版本号啦。

好啦,下面开始下面开始讲解gcc的常用参数啦o(∩_∩)o...

[参数详解]

-c

只激活预处理,编译,和汇编,也就是他只把程序做成obj文件

例子用法:

gcc-chello.c

他将生成.o的obj文件

-S

只激活预处理和编译,就是指把文件编译成为汇编代码。

例子用法

gcc-Shello.c

他将生成.s的汇编代码,你可以用文本编辑器察看

-E

只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里

面.

例子用法:

gcc-Ehello.c>pianoapan.txt

gcc-Ehello.c|more

慢慢看吧,一个helloword也要与处理成800行的代码

-o

制定目标名称,缺省的时候,gcc编译出来的文件是a.out,很难听,如果你和我有同感,改掉它,哈哈

例子用法

gcc-ohello.exehello.c(哦,windows用习惯了)

gcc-ohello.asm-Shello.c

-ansi

关闭gnuc中与ansic不兼容的特性,激活ansic的专有特性(包括禁止一

些asminlinetypeof关键字,以及UNIX,vax等预处理宏,

-Wall

显示警告信息

-O0

-O1

-O2

-O3

编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最

高  

-g

只是编译器,在编译的时候,产生调试信息。

-llibrary

制定编译的时候使用的库

例子用法

gcc-lcurseshello.c

使用ncurses库编译程序

-Ldir

制定编译的时候,搜索库的路径。

比如你自己的库,可以用它制定目录,不然

编译器将只在标准库的目录找。

这个dir就是目录的名称。

  

-gstabs

此选项以stabs格式声称调试信息,但是不包括gdb调试信息. 

-gstabs+

此选项以stabs格式声称调试信息,并且包含仅供gdb使用的额外调试信息.

-ggdb

此选项将尽可能的生成gdb的可以使用的调试信息.

-static  此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行.

-share  此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.

-traditional  试图让编译器支持传统的C语言特性

-fno-asm

此选项实现ansi选项的功能的一部分,它禁止将asm,inline和typeof用作

关键字。

-fno-strict-prototype

只对g++起作用,使用这个选项,g++将对不带参数的函数,都认为是没有显式

的对参数的个数和类型说明,而不是没有参数.

而gcc无论是否使用这个参数,都将对没有带参数的函数,认为城没有显式说

明的类型

-fthis-is-varialble

就是向传统c++看齐,可以使用this当一般变量使用.

-fcond-mismatch

允许条件表达式的第二和第三参数类型不匹配,表达式的值将为void类型

-funsigned-char

-fno-signed-char

-fsigned-char

-fno-unsigned-char

这四个参数是对char类型进行设置,决定将char类型设置成unsignedchar(前

两个参数)或者signedchar(后两个参数)

-includefile

包含某个代码,简单来说,就是便以某个文件,需要另一个文件的时候,就可以

用它设定,功能就相当于在代码中使用#include

例子用法:

gcchello.c-include/root/pianopan.h

-imacrosfile

将file文件的宏,扩展到gcc/g++的输入文件,宏定义本身并不出现在输入文件

-Dmacro

相当于C语言中的#definemacro

-Dmacro=defn

相当于C语言中的#definemacro=defn

-Umacro

相当于C语言中的#undefmacro

-undef

取消对任何非标准宏的定义

-Idir

在你是用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头

文件,如果没有找到,他回到缺省的头文件目录找,如果使用-I制定了目录,他

回先在你所制定的目录查找,然后再按常规的顺序去找.

对于#include,gcc/g++会到-I制定的目录查找,查找不到,然后将到系

统的缺省的头文件目录查找

-I-

就是取消前一个参数的功能,所以一般在-Idir之后使用

-idirafterdir

在-I的目录里面查找失败,讲到这个目录里面查找.

-iprefixprefix

-iwithprefixdir

一般一起使用,当-I的目录查找失败,会到prefix+dir下查找

-nostdinc

使编译器不再系统缺省的头文件目录里面找头文件,一般和-I联合使用,明确

限定头文件的位置

-nostdinC++

规定不在g++指定的标准路经中搜索,但仍在其他路径中搜索,.此选项在创建

libg++库使用

-C

在预处理的时候,不删除注释信息,一般和-E使用,有时候分析程序,用这个很

方便的 

-M

生成文件关联的信息。

包含目标文件所依赖的所有源代码

你可以用gcc-Mhello.c来测试一下,很简单。

 

-MM

和上面的那个一样,但是它将忽略由#include造成的依赖关系。

 

-MD

和-M相同,但是输出将导入到.d的文件里面

-MMD

和-MM相同,但是输出将导入到.d的文件里面

-Wa,option

此选项传递option给汇编程序;如果option中间有逗号,就将option分成多个选

项,然后传递给会汇编程序

-Wl.option

此选项传递option给连接程序;如果option中间有逗号,就将option分成多个选项,然后传递给会连接程序.

-xlanguagefilename设定文件所使用的语言,使后缀名无效,对以后的多个有效.也就是根据约定C语言的后缀名称是.c的,而C++的后缀名是.C或者.cpp,如果你很个性,决定你的C代码文件的后缀名是.pig哈哈,那你就要用这个参数,这个参数对他后面的文件名都起作用,除非到了下一个参数的使用。

可以使用的参数吗有下面的这些  `c',`objective-c',`c-header',`c++',`cpp-output',`assembler',and`assembler-with-cpp'.  看到英文,应该可以理解的。

  例子用法:

  gcc-xchello.pig

-xnonefilename  关掉上一个选项,也就是让gcc根据文件名后缀,自动识别文件类型  例子用法:

  gcc-xchello.pig-xnonehello2.c

-pipe  使用管道代替编译中临时文件,在使用非gnu汇编工具的时候,可能有些问题  gcc-pipe-ohello.exehello.c

-funsigned-char-fno-signed-char-fsigned-char-fno-unsigned-char  这四个参数是对char类型进行设置,决定将char类型设置成unsignedchar(前两个参数)或者signedchar(后两个参数)

GCC的参数是很多的,这也只是部分。

不过对于初学者来说,一时之间掌握这么多的参数也是有点困难的,不过一般推荐使用命令:

gcc-Wallhello.c-ohello就足够啦。

一般要使用-Wall这个参数,他可以列出源程序在编译过程中出现的错误警告等信息,这是很有帮助的,注意:

-Wall这个参数是在编译过程中使用的,若先把源程序编译成目标文件,则在链接过程中不要使用这个参数。

你还可以再加个-v参数:

列出比较详细的信息,(在标准错误)显示执行编译阶段的命令.同时显示编译器驱动程序,预处理器,编译器的版本号.

这些在我们平时使用的过程中应该已经足够啦,若还想了解其他的一些参数,可以下载gcc的帮助文档有时间自己研究下。

四:

多文件编译、连接

如果原文件分布于多个文件中:

file1.c,file2,c

$gcc-Wallfile1.cfile2.c-oname

若对其中一个文件作了修改,则可只重新编译该文件,再连接所有文件:

$gcc-Wall-cfile2.c

$gccfile1.cfile2.o-cname

注意:

有些编译器对命令行中的.o文件的出现顺序有限制:

含有某函数定义的文件必须出现在含有调用该函数的文件之后。

好在GCC无此限制。

编译预处理

在程序中包含与连接库对应的头文件是很重要的方面,要使用库,就一定要能正确地引用头文件。

一般在代码中通过#include引入头文件,如果头文件位于系统默认的包含路径(/usr/includes),则只需在#include中给出头文件的名字,不需指定完整路径.但若要包含的头文件位于系统默认包含路径之外,则有其它的工作要做:

可以(在源文件中)同时指定头文件的全路径.但考虑到可移植性,最好通过-I在调用gcc的编译命令中指定。

下面看这个求

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1