没有合适的资源?快使用搜索试试~ 我知道了~
gcc开始 实例引导
需积分: 3 12 下载量 30 浏览量
2008-10-23
11:20:57
上传
评论
收藏 88KB DOC 举报
温馨提示
试读
21页
作者通过一简单小游戏教你gcc原理及命令操作,可快速入门并掌握,个人认为很实用
资源详情
资源评论
资源推荐
GCC——一切从这里开始
作者:Lorne Bailey
摘要:
要想读懂本文,你需要对 C 语言有基本的了解,本文将介绍如何使用 gcc 编译器。
首先,我们介绍如何在命令行方式下使用编译器编译简单的 C 源代码。然后,我
们简要介绍一下编译器究竟作了那些工作,以及如何控制编译过程。我们也简要
介绍了调试器的使用方法。
GCC rules
你能想象使用封闭源代码的私有编译器编译自由软件吗?你怎么知道编译器在你
的可执行文件中加入了什么?可能会加入各种后门和木马。Ken Thompson 是一
个
著名的黑客,他编写了一个编译器,当编译器编译自己时,就在'login'程序中
留下后门和永久的木马。幸运的是,我们有了 gcc。当你进行 congure; make;
make install 时, gcc 在幕后做了很多繁重的工作。如何才能让 gcc 为我们工作
呢?我们将开始编写一个纸牌游戏,不过我们只是为了演示编译器的功能,所以
尽可能地精简了代码。我们将从头开始一步一步地做,以便理解编译过程,了解
为了制作可执行文件需要做些什么,按什么顺序做。我们将看看如何编译 C 程序
,以及如何使用编译选项让 gcc 按照我们的要求工作。步骤(以及所用工具)如
下: 预编译 (gcc -E), 编译 (gcc), 汇编 (as),和 连接 (ld)。
开始...
首先,我们应该知道如何调用编译器。实际上,这很简单。我们将从那个著名的
第一个 C 程序开始。(各位老前辈,请原谅我)。
#include <stdio.h>
int main()
{
printf("Hello World!");
}
把这个文件保存为 game.c。 你可以在命令行下编译它:
gcc game.c
在默认情况下,C 编译器将生成一个名为 a.out 的可执行文件。你可以键入如下
命令运行它:
a.out
Hello World
每一次编译程序时,新的 a.out 将覆盖原来的程序。你无法知道是哪个程序创
建了 a.out。我们可以通过使用 -o 编译选项,告诉 gcc 我们想把可执行文件叫
什么名字。我们将把这个程序叫做
game,我们可以使用任何名字,因为 C 没有 Java 那样的命名限制。
gcc -o game game.c
game
Hello World
到现在为止,我们离一个有用的程序还差得很远。如果你觉得沮丧,你可以想一
想我们已经编译并运行了一个程序。因为我们将一点一点为这个程序添加功能,
所以我们必须保证让它能够运行。似乎每个刚开始学编程的程序员都想一下子编
一个 1000 行的程序,然后一次修改所有的错误。没有人,我是说没有人,能做到
这个。你应该先编一个可以运行的小程序,修改它,然后再次让它运行。这可以
限制你一次修改的错误数量。另外,你知道刚才做了哪些修改使程序无法运行,
因此你知道应该把注意力放在哪里。这可以防止这样的情况出现:你认为你编写
的东西应该能够工作,它也能通过编译,但它就是不能运行。请切记,能够通过
编译的程序并不意味着它是正确的。
下一步为我们的游戏编写一个头文件。头文件把数据类型和函数声明集中到了一
处。这可以保证数据结构定义的一致性,以便程序的每一部分都能以同样的方式
看待一切事情。
#ifndef DECK_H
#dene DECK_H
#dene DECKSIZE 52
typedef struct deck_t
{
int card[DECKSIZE];
/* number of cards used */
int dealt;
}deck_t;
#endif /* DECK_H */
把这个文件保存为 deck.h。只能编译 .c 文件,所以我们必须修改 game.c。在
game.c 的第 2 行,写上 #include "deck.h"。在第 5 行写上 deck_t deck;。为
了
保证我们没有搞错,把它重新编译一次。
gcc -o game game.c
如果没有错误,就没有问题。如果编译不能通过,那么就修改它直到能通过为止
。
预编译
编译器是怎么知道 deck_t
类型是什么的呢?因为在预编译期间,它实际上把"deck.h"文件复制到了"game.
c"文件中。源代码中的预编译指示以"#"为前缀。你可以通过在 gcc 后加上 -E 选
项来调用预编译器。
gcc -E -o game_precompile.txt game.c
wc -l game_precompile.txt
3199 game_precompile.txt
几乎有 3200 行的输出!其中大多数来自 stdio.h 包含文件,但是如果你查看这
个文件的话,我们的声明也在那里。如果你不用 -o 选项指定输出文件名的话,
它就输出到控制台。预编译过程通过完成三个主要任务给了代码很大的灵活性。
1. 把"include"的文件拷贝到要编译的源文件中。
2. 用实际值替代"dene"的文本。
3. 在调用宏的地方进行宏替换。
这就使你能够在整个源文件中使用符号常量(即用 DECKSIZE 表示一付牌中的纸
牌
数量),而符号常量是在一个地方定义的,如果它的值发生了变化,所有使用符
号常量的地方都能自动更新。在实践中,你几乎不需要单独使用 -E 选项,而是
让它把输出传送给编译器。
编译
作为一个中间步骤,gcc 把你的代码翻译成汇编语言。它一定要这样做,它必须
通过分析你的代码搞清楚你究竟想要做什么。如果你犯了语法错误,它就会告诉
你,这样编译就失败了。人们有时会把这一步误解为整个过程。但是,实际上还
有许多工作要 gcc 去做呢。
汇编
as 把汇编语言代码转换为目标代码。事实上目标代码并不能在 CPU 上运行,但它
离完成已经很近了。编译器选项 -c 把 .c 文件转换为以 .o 为扩展名的目标文
件。 如果我们运行
gcc -c game.c
我们就自动创建了一个名为 game.o 的文件。这里我们碰到了一个重要的问题。
我
们可以用任意一个 .c 文件创建一个目标文件。正如我们在下面所看到的,在连
接步骤中我们可以把这些目标文件组合成可执行文件。让我们继续介绍我们的例
子.因为我们正在编写一个纸牌游戏,我们已经把一付牌定义为 deck_t,我们
将编写一个洗牌函数。这个函数接受一个指向 deck 类型的指针,并把一付随机的
牌装入 deck 类型。它使用'drawn'
数组跟踪记录那些牌已经用过了。这个具有 DECKSIZE 个元素的数组可以防止我
们
重复使用一张牌。
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "deck.h"
static time_t seed = 0;
void shuFe(deck_t *pdeck)
{
/* Keeps track of what numbers have been used */
int drawn[DECKSIZE] = {0};
int i;
/* One time initialization of rand */
if(0 == seed)
{
seed = time(NULL);
srand(seed);
}
for(i = 0; i < DECKSIZE; i++)
{
int value = -1;
do
{
value = rand() % DECKSIZE;
}
while(drawn[value] != 0);
/* mark value as used */
drawn[value] = 1;
/* debug statement */
printf("%i\n", value);
pdeck->card[i] = value;
}
pdeck->dealt = 0;
return;
剩余20页未读,继续阅读
Ellen_2007
- 粉丝: 0
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0