GCC使用手册与常用命令Word文档格式.docx
- 文档编号:20757334
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:19
- 大小:30.99KB
GCC使用手册与常用命令Word文档格式.docx
《GCC使用手册与常用命令Word文档格式.docx》由会员分享,可在线阅读,更多相关《GCC使用手册与常用命令Word文档格式.docx(19页珍藏版)》请在冰豆网上搜索。
我们将把这个程序叫做game,我们可以使用任何名字,因为C没有Java那样的命名限制。
gcc-ogamegame.c
game
到现在为止,我们离一个有用的程序还差得很远。
如果你觉得沮丧,你可以想一想我们已经编译并运行了一个程序。
因为我们将一点一点为这个程序添加功能,所以我们必须保证让它能够运行。
似乎每个刚开始学编程的程序员都想一下子编一个1000行的程序,然后一次修改所有的错误。
没有人,我是说没有人,能做到这个。
你应该先编一个可以运行的小程序,修改它,然后再次让它运行。
这可以限制你一次修改的错误数量。
另外,你知道刚才做了哪些修改使程序无法运行,因此你知道应该把注意力放在哪里。
这可以防止这样的情况出现:
你认为你编写的东西应该能够工作,它也能通过编译,但它就是不能运行。
请切记,能够通过编译的程序并不意味着它是正确的。
下一步为我们的游戏编写一个头文件。
头文件把数据类型和函数声明集中到了一处。
这可以保证数据结构定义的一致性,以便程序的每一部分都能以同样的方式看待一切事情。
#ifndefDECK_H
#defineDECK_H
#defineDECKSIZE52
typedefstructdeck_t
intcard[DECKSIZE];
/*numberofcardsused*/
intdealt;
}deck_t;
#endif/*DECK_H*/
把这个文件保存为deck.h。
只能编译.c文件,所以我们必须修改game.c。
在game.c的第2行,写上#include"
deck.h"
。
在第5行写上deck_tdeck;
为了保证我们没有搞错,把它重新编译一次。
如果没有错误,就没有问题。
如果编译不能通过,那么就修改它直到能通过为止。
预编译
编译器是怎么知道deck_t类型是什么的呢?
因为在预编译期间,它实际上把"
文件复制到了"
game.c"
文件中。
源代码中的预编译指示以"
#"
为前缀。
你可以通过在gcc后加上-E选项来调用预编译器。
gcc-E-ogame_precompile.txtgame.c
wc-lgame_precompile.txt
3199game_precompile.txt
几乎有3200行的输出!
其中大多数来自stdio.h包含文件,但是如果你查看这个文件的话,我们的声明也在那里。
如果你不用-o选项指定输出文件名的话,它就输出到控制台。
预编译过程通过完成三个主要任务给了代码很大的灵活性。
1.把"
include"
的文件拷贝到要编译的源文件中。
2.用实际值替代"
define"
的文本。
3.在调用宏的地方进行宏替换。
这就使你能够在整个源文件中使用符号常量(即用DECKSIZE表示一付牌中的纸牌数量),而符号常量是在一个地方定义的,如果它的值发生了变化,所有使用符号常量的地方都能自动更新。
在实践中,你几乎不需要单独使用-E选项,而是让它把输出传送给编译器。
编译
作为一个中间步骤,gcc把你的代码翻译成汇编语言。
它一定要这样做,它必须通过分析你的代码搞清楚你究竟想要做什么。
如果你犯了语法错误,它就会告诉你,这样编译就失败了。
人们有时会把这一步误解为整个过程。
但是,实际上还有许多工作要gcc去做呢。
汇编
as把汇编语言代码转换为目标代码。
事实上目标代码并不能在CPU上运行,但它离完成已经很近了。
编译器选项-c把.c文件转换为以.o为扩展名的目标文件。
如果我们运行
gcc-cgame.c
我们就自动创建了一个名为game.o的文件。
这里我们碰到了一个重要的问题。
我们可以用任意一个.c文件创建一个目标文件。
正如我们在下面所看到的,在连接步骤中我们可以把这些目标文件组合成可执行文件。
让我们继续介绍我们的例子。
因为我们正在编写一个纸牌游戏,我们已经把一付牌定义为deck_t,我们将编写一个洗牌函数。
这个函数接受一个指向deck类型的指针,并把一付随机的牌装入deck类型。
它使用'
drawn'
数组跟踪记录那些牌已经用过了。
这个具有DECKSIZE个元素的数组可以防止我们重复使用一张牌。
stdlib.h>
time.h>
#include"
statictime_tseed=0;
voidshuffle(deck_t*pdeck)
/*Keepstrackofwhatnumbershavebeenused*/
intdrawn[DECKSIZE]={0};
inti;
/*Onetimeinitializationofrand*/
if(0==seed)
{
seed=time(NULL);
srand(seed);
}
for(i=0;
i<
DECKSIZE;
i++)
intvalue=-1;
do
value=rand()%DECKSIZE;
while(drawn[value]!
=0);
/*markvalueasused*/
drawn[value]=1;
/*debugstatement*/
%i\n"
value);
pdeck->
card[i]=value;
dealt=0;
return;
把这个文件保存为shuffle.c。
我们在这个代码中加入了一条调试语句,以便运行时,能输出所产生的牌号。
这并没有为我们的程序添加功能,但是现在到了关键时刻,我们看看究竟发生了什么。
因为我们的游戏还在初级阶段,我们没有别的办法确定我们的函数是否实现了我们要求的功能。
使用那条printf语句,我们就能准确地知道现在究竟发生了什么,以便在开始下一阶段之前我们知道牌已经洗好了。
在我们对它的工作感到满意之后,我们可以把那一行语句从代码中删掉。
这种调试程序的技术看起来很粗糙,但它使用最少的语句完成了调试任务。
以后我们再介绍更复杂的调试器。
请注意两个问题。
1.我们用传址方式传递参数,你可以从'
&
'
(取地址)操作符看出来。
这把变量的机器地址传递给了函数,因此函数自己就能改变变量的值。
也可以使用全局变量编写程序,但是应该尽量少使用全局变量。
指针是C的一个重要组成部分,你应该充分地理解它。
2.我们在一个新的.c文件中使用函数调用。
操作系统总是寻找名为'
main'
的函数,并从那里开始执行。
shuffle.c中没有'
函数,因此不能编译为独立的可执行文件。
我们必须把它与另一个具有'
函数并调用'
shuffle'
的程序组合起来。
运行命令
gcc-cshuffle.c
并确定它创建了一个名为shuffle.o的新文件。
编辑game.c文件,在第7行,在deck_t类型的变量deck声明之后,加上下面这一行:
shuffle(&
deck);
现在,如果我们还象以前一样创建可执行文件,我们就会得到一个错误
/tmp/ccmiHnJX.o:
Infunction`main'
:
/tmp/ccmiHnJX.o(.text+0xf):
undefinedreferenceto`shuffle'
collect2:
ldreturned1exitstatus
编译成功了,因为我们的语法是正确的。
但是连接步骤却失败了,因为我们没有告诉编译器'
函数在哪里。
那么,到底什么是连接?
我们怎样告诉编译器到哪里寻找这个函数呢?
连接
连接器ld,使用下面的命令,接受前面由as创建的目标文件并把它转换为可执行文件
gcc-ogamegame.oshuffle.o
这将把两个目标文件组合起来并创建可执行文件game。
连接器从shuffle.o目标文件中找到shuffle函数,并把它包括进可执行文件。
目标文件的真正好处在于,如果我们想再次使用那个函数,我们所要做的就是包含"
文件并把shuffle.o目标文件连接到新的可执行文件中。
象这样的代码重用是经常发生的。
虽然我们并没有编写前面作为调试语句调用的printf函数,连接器却能从我们用#include<
语句包含的文件中找到它的声明,并把存储在C库(/lib/libc.so.6)中的目标代码连接进来。
这种方式使我们可以使用已能正确工作的其他人的函数,只关心我们所要解决的问题。
这就是为什么头文件中一般只含有数据和函数声明,而没有函数体。
一般,你可以为连接器创建目标文件或函数库,以便连接进可执行文件。
我们的代码可能产生问题,因为在头文件中我们没有放入任何函数声明。
为了确保一切顺利,我们还能做什么呢?
另外两个重要选项
-Wall选项可以打开所有类型的语法警告,以便帮助我们确定代码是正确的,并且尽可能实现可移植性。
当我们使用这个选项编译我们的代码时,我们将看到下述警告:
game.c:
9:
warning:
implicitdeclarationoffunction`shuffle'
这让我们知道还有一些工作要做。
我们需要在头文件中加入一行代码,以便告诉编译器有关shuffle函数的一切,让它可以做必要的检查。
听起来象是一种狡辩,但这样做可以把函数的定义与实现分离开来,使我们能在任何地方使用我们的函数,只要包含新的头文件并把它连接到我们的目标文件中就可以了。
下面我们就把这一行加入deck.h中。
voidshuffle(deck_t*pdeck);
这就可以消除那个警告信息了。
另一个常用编译器选项是优化选项-O#(即-O2)。
这是告诉编译器你需要什么级别的优化。
编译器具有一整套技巧可以使你的代码运行得更快一点。
对于象我们这种小程序,你可能注意不到差别,但对于大型程序来说,它可以大幅度提高运行速度。
你会经常碰到它,所以你应该知道它的意思。
调试
我们都知道,代码通过了编译并不意味着它按我们得要求工作了。
你可以使用下面的命令验证是否所有的号码都被使用了
game|sort-n|less
并且检查有没有遗漏。
如果有问题我们该怎么办?
我们如何才能深入底层查找错误呢?
你可以使用调试器检查你的代码。
大多数发行版都提供著名的调试器:
gdb。
如果那些众多的命令行选项让你感到无所适从,那么你可以使用KDE提供的一个很好的前端工具KDbg。
还有一些其它的前端工具,它们都很相似。
要开始调试,你可以选择File->
Executable然后找到你的game程序。
当你按下F5键或选择Execution->
从菜单运行时,你可以在另一个窗口中看到输出。
怎么回事?
在那个窗口中我们什么也看不到。
不要担心,KDbg没有出问题。
问题在于我们在可执行文件中没有加入任何调试信息,所以KDbg不能告诉我们内部发生了什么。
编译器选项-g可以把必要的调试信息加入目标文件。
你必须用这个选项编译目标文件(扩展名为.o),所以命令行成了:
gcc-g-cshuffle.cgame.c
gcc-g-ogamegame.oshuffle.o
这就把钩子放入了可执行文件,使gdb和KDbg能指出运行情况。
调试是一种很重要的技术,很值得你花时间学习如何使用。
调试器帮助程序员的方法是它能在源代码中设置“断点”。
现在你可以用右键单击调用shuffle函数的那行代码,试着设置断点。
那一行边上会出现一个红色的小圆圈。
现在当你按下F5键时,程序就会在那一行停止执行。
按F8可以跳入shuffle函数。
呵,我们现在可以看到shuffle.c中的代码了!
我们可以控制程序一步一步地执行,并看到究竟发生了什么事。
如果你把光标暂停在局部变量上,你将能看到变量的内容。
太好了。
这比那条printf语句好多了,是不是?
小结
本文大体介绍了编译和调试C程序的方法。
我们讨论了编译器走过的步骤,以及为了让编译器做这些工作应该给gcc传递哪些选项。
我们简述了有关连接共享函数库的问题,最后介绍了调试器。
真正了解你所从事的工作还需要付出许多努力,但我希望本文能让你正确地起步。
你可以在gcc、as和ld的man和infopage中找到更多的信息。
自己编写代码可以让你学到更多的东西。
作为练习你可以以本文的纸牌游戏为基础,编写一个21点游戏。
那时你可以学学如何使用调试器。
使用GUI的KDbg开始可以更容易一些。
如果你每次只加入一点点功能,那么很快就能完成。
切记,一定要保持程序一直能运行!
要想编写一个完整的游戏,你需要下面这些内容:
∙一个纸牌玩家的定义(即,你可以把deck_t定义为player_t)。
∙一个给指定玩家发一定数量牌的函数。
记住在纸牌中要增加“已发牌”的数量,以便能知道还有那些牌可发。
还要记住玩家手中还有多少牌。
∙一些与用户的交互,问问玩家是否还要另一张牌。
∙一个能打印玩家手中的牌的函数。
card等于value%13(得数为0到12),suit等于value/13(得数为0到3)。
∙一个能确定玩家手中的value的函数。
Ace的value为零并且可以等于1或11。
King的value为12并且可以等于10。
1.前言
GCC编译器的手册(GCCMANUAL)的英文版已经非常全面,并且结构也非常完善了,只是一直都没有中文的版本,我这次阅读了GCC编译器的主要内容,对手册的内容进行了结构性的了解,认为有必要对这次阅读的内容进行整理,为以后的工作做准备。
由于我对这个英文手册的阅读也仅仅是结构性的。
因此有很多地方并没有看,所以这篇文档的内容我也只能写出部分,对于以后需要详细了解的地方,会再往这篇文档中增添内容,需要增添的内容主要是编译器的各种开关。
2.GCC功能介绍
GCC编译器完成从C、C++、objective-C等源文件向运行在特定CPU硬件上的目标代码的转换(这是任何一个编译器需要完成的任务)。
GCC能够处理的源文件分为C、C++、Objective-C、汇编语言等。
对于这些源文件,用他们的后缀名进行标示。
GCC能够处理的后缀有:
a.*.c*.C
(C语言)
b.*.cxx
*.cc(C++语言)
c.*.m
(面向对象的C)
d.*.i
(预处理后的C语言源文件)
e.*.ii
(预处理后的C++语言源文件)
f.*.s*.S
(汇编语言)
h.*.h
(头文件)
目标文件可以是:
a.*.o
编译连接后的目标文件
b.*.a
库文件
编译器把编译生成目标代码的任务分为以下4步:
a.预处理,把预处理命令扫描处理完毕;
b.编译,把预处理后的结果编译成汇编或者目标模块;
c.汇编,把编译出来的结果汇编成具体CPU上的目标代码模块;
d.连接,把多个目标代码模块连接生成一个大的目标模块;
3.GCC开关
GCC的运行开关共分为11类,这是类开关从11个方面控制着GCC程序的运行,以达到特定的编译目的。
3.1.全局开关(OVERALLOPTIONS)
全局开关用来控制在“GCC功能介绍”中的GCC的4个步骤的运行,在缺省的情况下,这4个步骤都是要执行的,但是当给定一些全局开关后,这些步骤就会在某一步停止执行,这产生中间结果,例如可能你只是需要中间生成的预处理的结果或者是汇编文件(比如拟的目的是为了看某个CPU上的汇编语言怎么写)。
3.1.1.–xlanguage
对于源文件是用什么语言编写的,可以通过文件名的后缀来标示,也可以用这开关。
指定输入文件是什么语言编写的,language可以是如下的内容
a.c
b.objective-c
c.c-header
d.c++
e.cpp-output
f.assembler
g.assembler-with-cpp
3.1.2.–xnone
把上一节介绍的-x开关都给关掉了。
3.1.3.–c
编译成把源文件目标代码,不做连接的动作。
3.1.4.–S
把源文件编译成汇编代码,不做汇编和连接的动作。
3.1.5.–E
只把源文件进行预处理之后的结果输出来。
不做编译,汇编,连接的动作。
3.1.6.–ofile
指明输出文件名是file。
3.1.7.–v
把整个编译过程的输出信息都给打印出来。
3.1.8.–pipe
由于gcc的工作分为好几步才完成,所以需要在过程中生成临时文件,使用-pipe就是用管道替换临时文件。
3.2.语言相关开关(LanguageOptions)
用来处理和语言相关的控制开关。
3.2.1.–ansi
这个开关让GCC编译器把所有的gnu的编译器特性都给关掉,让你的程序可以和ansi标准兼容。
除了以上的开关外,语言相关开关还有很多,如果在以后的工作学习中遇到了再加不迟!
3.3.预处理开关(PreprocessorOptions)
用来控制预处理所设置的开关。
3.3.1.–includefile
在编译之前,把file包含进去,相当于在所有编译的源文件最前面加入了一个#include<
file>
语句,这样做更“省油”。
3.3.2.–imacrosfile
同-includefile一样。
不过这个文件在具体编译的时候只有里面定义的宏才起作用,所以值用来在file文件里面定义宏。
3.3.3.–nostdinc
在搜寻include的文件路径中去掉标准的c语言头文件搜索路径,例如stdio.h文件就是放在标准头文件搜索路径下。
3.3.4.–nostdinc++
同上,只是去掉的是标准C++语言的头文件搜索路径。
3.3.5.–C
同-E参数配合使用。
让预处理后的结果,把注释保留,让人能够比较好读它。
3.3.6.–Dmacro
把macro定义为字符串’1’。
3.3.7.–Dmacro=defn
把macro定义为defn。
3.3.8.–Umacro
把对macro的定义取消。
除了以上的开关外,预处理相关开关还有很多,如果在以后的工作学习中遇到了再加不迟!
3.4.
汇编开关(AssemblerOption)
用来控制汇编行为的开关。
3.4.1.–Wa,option
把option作为开关送给汇编程序。
如果option里面有逗号,则作为好几行进行处理。
3.5.连接开关(LinkerOptions)
用来控制连接过程的开关选项。
3.5.1.object-file-name
3.5.2.–llibrary
连接库文件开关。
例如-lugl,则是把程序同libugl.a文件进行连接。
3.5.3.–lobjc
这个开关用在面向对象的C语言文件的库文件处理中。
3.5.4.–nostartfiles
在连接的时候不把系统相关的启动代码连接进来。
3.5.5.
–nostdlib
在连接的时候不把系统相关的启动文件和系统相关的库连接进来。
3.5.6.–static
在一些系统上支持动态连接,这个开关则不允许动态连接。
3.5.7.–shared
生成可共享的被其他程序连接的目标模块。
连接相关的开关还有一些,以后需要的时候再补。
3.6.目录相关开关(DirectoryOptions)
用于定义与目录操作相关的开关。
3.6.1.–Idir
宏include需要搜寻的目录。
3.6.2.–I-
与-I开关类似。
3.6.3.–Ldir
搜寻库文件(*.a)的路径。
和目录相关的开关还有很多,以后需要再加。
3.7.警告开关(WarningOptions)
与警告处理相关的开关。
3.7.1.–fsyntax-only
只检查代码中的语法错误,但并没有输出。
3.7.2.–w
禁止一切警告信息打印出来。
3.7.3.–Wno-import
禁止对宏#import提出警告。
3.7.4.–pedantic
3.7.5.–pedantic-errors
3.7.6.–W
还有很多与警告处理相关的开关,以后再补。
3.8.调试开关(DebuggingOptions)
3.8.1.–g
把调试开关打开,让编译的目标文件有调试信息。
还有很多与调试处理相关的开关,以后再补。
3.9.优化开关(OptimizationOptions)
-O1–O2–O3–O0,这些开关分别控制优化的强度,-O3最强。
3.10.目标机开关(TargetOptions)
3.10.1.–bmachine
在有的时候,Gcc编译器编译出来的目标代码并不是在运行这个编译动作的机器上运行而是另外一台机器,这种编译叫做交叉编译,用来运行
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- GCC 使用手册 常用命令