Вы находитесь на странице: 1из 8

LinuxFocus article number 229

http://linuxfocus.org

GCC a raiz para tudo

by Lorne Bailey

Abstract:

<sherm_pbody/at/yahoo.com>

Este artigo assume que sabe as bases da linguagem C e introduzirlhe o


gcc como um compilador. Certificarnosemos que consegue invocar o
compilador a partir da linha de comandos utilizando cdigo fonte C simples.
Depois veremos muito rapidamente o que est a acontecer agora e como
O Lorne vive em Chicago e
pode controlar a compilao dos seus programas. Daremos uma pequena
trabalha como consultor
informtico, especializado em entrada em como utilizar um depurador.
obter dados de e para bases
_________________ _________________ _________________
de dados Oracle. Desde que
se mudou para um ambiente
de programao *nix, evitou
por completo a 'DLL Hell'.
Est, presentemente a
trabalhar no mestrado sobre
Cincia de Computao.
About the author:

Regras do GCC
Conseguese imaginar a compilar software livre com um compilador proprietrio e fechado? Como que
sabe o que vai no seu executvel? Pode haver qualquer tipo de "back door" ou cavalo de Tria. O Ken
Thompson, numa das piratarias de todos os tempos, escreveu um compilador que deixava uma "back door" no
programa de 'login' e perpetuava o cavalo de Tria quando o compilador se apercebia que estava a compilar a
si mesmo. Leia a descrio dele para todos clssicos de todos os tempos aqui. Felizmente, temos o gcc.
Sempre que faz um configure; make; make install o gcc faz um trabalho pesado que no se v.
Como que fazemos o gcc trabalhar para ns? Comearemos por escrever um jogo de cartas, mas s
escreveremos o necessrio para demonstrar a funcionalidade do compilador. Visto que estamos a comear do
zero, preciso compreender o processo de compilao para saber o que deve ser feiro para se ter um
executvel e em que ordem. Daremos uma visto de olhos geral como um programa C compilado e as opes
que o gcc tem para fazer o que queremos. Os passos (e os utilitrios que os fazem) so Prcompilao (gcc
E), Compilao (gcc), Assemblagem (as), e Linkagem (ld) Ligao.

1/8

No Princpio...
Primeiro pensamento, devamos saber como invocar o compilador em primeiro lugar. realmente simples.
Comearemos com o clssico de todos os tempos, o primeiro programa C. (Os de velhos tempos que me
perdoem).
#include <stdio.h>
int main()
{
printf("Hello World!\n");
}

Guarde este ficheiro como game.c. Pode compillo na linha de comandos, correndo:
gcc game.c

Por omisso, o compilador C cria um executvel com o nome de a.out. Pode corrlo digitando:
a.out
Hello World

Cada vez que compilar o programa, o novo a.out sobrepor o programa anterior. No conseguir dizer que
programa criou o a.out actual. Podemos resolver este problema dizendo ao gcc o nome que queremos dar
com a opo o. Chamaremos este programa de game, contudo podamos nomelo com qualquer coisa,
visto que o C no tem as restries que o Java tem, para os nomes.
gcc o game game.c
game
Hello World

At este ponto, ainda estamos longe de um programa til. Se pensa que isto uma coisa m, deve reconsiderar
o facto que temos um programa que compila e corre. medida que adicionarmos funcionalidade, a pouco e
pouco, queremos certificarnos que o mantemos capaz de correr. Parece que todos os programadores
iniciantes querem escrever 1,000 linhas de cdigo e depois corrigilas de uma vez s. Ningum, mas mesmo
ningum pode fazer isto. Voc faz um programa pequeno que correm faz as alteraes e tornao executvel
novamente. Isto limita os erros que tem de corrigir de uma s vez. E ainda por cima, voc sabe exactamente o
que fez e que no trabalha, ento sabe onde concentrarse. Isto evitalhe criar algo que voc pensa que
trabalha e at compile mas nunca se torna num executvel. Lembrese que s por ter compilado no quer
dizer que esteja correcto.
O nosso prximo passo criar um ficheiro cabealho para o nosso jogo. Um ficheiro cabealho concentra os
tipos de dados e a declarao de funes num s stio. Isto assegura que as estruturas de dados esto definidas
consistentemente, assim qualquer parte do nosso programa v tudo, exactamente do mesmo modo.
#ifndef DECK_H
#define DECK_H
#define DECKSIZE 52
typedef struct deck_t
{

2/8

int card[DECKSIZE];
/* number of cards used */
int dealt;
}deck_t;
#endif /* DECK_H */

Guarde este ficheiro como deck.h. S o ficheiro .c que compilado, assim temos de alterar o nosso
game.c. Na linha 2 do game.c, escreva #include "deck.h". Na linha 5, escreva deck_t deck; para
ter a certeza que no falhmos nada, compileo novamente.
gcc o game game.c

Se no houver erros, no h problema. Se no compilar resolvao at compilar.

Prcompilao
Como que o compilador sabe que tipo o deck_t ? Porque durante a prcompilao, ele, na verdade
copia o ficheiro "deck.h" para dentro do ficheiro "game.c". As directivas do prcompilador no cdigo fonte
comeam por um "#". Pode invocar o prcompilador atravs do frontend do gcc com a opo E.
gcc E o game_precompile.txt game.c
wc l game_precompile.txt
3199 game_precompile.txt

Praticamente 3,200 linhas de sada! A maioria delas vem do ficheiro includo stdio.h, mas se der uma vista
de olhos nele, as suas declaraes tambm l esto. Se no der um nome de ficheiro para sada com a opo
o, ele escreve para a consola. O processo de prcompilao d mais flexibilidade ao cdigo ao atingir trs
grandes objectivos.
1. Copia os ficheiros "#included" no cdigo fonte para serem compilados.
2. Substirui o texto "#define" pelo seu valor actual.
3. Substitui as macros nas linhas onde so chamadas.
Isto permitelhe ter constantes com nomes (por exemplo, a DECKSIZE representa o nmero de cartas num
baralho) utilizadas ao longo do cdigo e definidas num s stio e automaticamente actualizadas sempre que o
seu valor se altera. Na prtica, quase num utilizar a opo E isoladamente, mas deixar passar a sua sada
para o compilador.

Compilao
Como um passo intermedirio, o gcc traduz o seu cdigo em linguagem Assembler. Para fazer isto, ele deve
descobrir o que que tinha inteno de fazer ao passar por todo o seu cdigo. Se cometer um erro de sintaxe
ele dirlhe e a compilao falhar. Muitas vezes as pessoas confundem este passo com todo o processo
inteiro. Mas ainda h mais trabalho para o gcc fazer.

3/8

Assemblagem
O as transforma o cdigo Assembler em cdigo objecto. O cdigo objecto no pode ainda correr no CPU, as
est muito perto. A opo do compilador c transforma um ficheiro .c num ficheiro objecto com a extenso
.o. Se corrermos:
gcc c game.c

criamos automaticamente um ficheiro chamado game.o. Aqui camos num ponto importante. Podemos tomar
qualquer ficheiro .c e criar um ficheiro objecto a partir dele. Como vemos abaixo, podemos combinar estes
ficheiros objecto em executveis no passo de Ligao. Continuemos com o nosso exemplo. Visto estarmos a
programar um jogo de cartas e definimos um baralho de cartas como um deck_t, escreveremos um funo
para baralhar o baralho. Esta funo recebe um ponteiro do tipo deck e corregao com um valores aleatrios
para as cartas. Mantm rasto das cartas j desenhadas, com o vector de 'desenho'. Este vector com membros
do DECKSIZE evitanos duplicar o valor de uma carta.
#include
#include
#include
#include

<stdlib.h>
<stdio.h>
<time.h>
"deck.h"

static time_t seed = 0;


void shuffle(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;
}

Guarde este ficheiro como shuffle.c. Pusemos uma frase de depurao no cdigo para quando correr,
escrever o nmero das cartas que gera. Isto no adiciona nenhuma funcionalidade ao programa, mas agora,
crucial para vermos o que se passa. Visto estarmos somente a comear o nosso jogo, no temos outro modo
seno que termos a certeza que a nossa funo est a fazer o que pretendemos. Com a frase printf, podemos
4/8

ver exactamente o que est acontecer e assim quando passarmos para a prxima fase sabemos que o baralho
esta bem baralhado. Depois de estarmos satisfeitos com o seu funcionamento podemos remover esta linha do
nosso cdigo. Esta tcnica de fazer depurao aos programas parece arcaica mas flo com um mnimo de
trabalho irrelevante. Discutiremos mais tardes depuradores mais sofisticados.
Note duas coisas.
1. Passamos por parmetro o seu endereo, pode dizer isto pelo '&' (endereo de) operador. Isto passa o
endereo de mquina da varivel para a funo, assim a funo pode alterar a prpria varivel.
possvel programar com variveis globais, mas deviam ser utilizadas raramente. Os ponteiros so uma
parte importante do C e devia entendelos tambm.
2. Estamos a utilizar uma chamada de funo a partir do novo ficheiro .c. O sistema operativo procura
sempre por uma funo chamada 'main' e comea a sua execuo a. O shuffle.c no tem uma
funo 'main' por conseguinte no pode ser um executvel por si s. Devemos combinlo com outro
programa que tenha uma funo 'main' e que chame a funo shuffle.
Corra o comando
gcc c shuffle.c

e certifiquese que cria um novo ficheiro chamado shuffle.o. Edite o ficheiro game.c, e na linha 7, aps a
declarao da varivel deck_t deck, adicione a linha
shuffle(&deck);

Agora, se tentarmos criar um executvel do mesmo modo como antes obtemos um erro
gcc o game game.c
/tmp/ccmiHnJX.o: In function `main':
/tmp/ccmiHnJX.o(.text+0xf): undefined reference to `shuffle'
collect2: ld returned 1 exit status

O compilador teve sucesso porque a nossa sintaxe estava correcta. A fase de ligao falhou porque no
dissemos ao compilador onde se encontra a funo 'shuffle'. O que que a ligao e como que dizemos ao
compilador onde pode encontrar esta funo? Ligao
O linker, ld, pega no cdigo objecto previamente criado com as e transformao num executvel atravs do
comando
gcc o game game.o shuffle.o

Isto combinar os dois objectos e criar o executvel game.


O linker encontra a funo shuffle a partir do objecto shuffle.o e incluio no executvel. A verdadeira
beleza dos ficheiros objecto vem do facto se quisermos utilizarmos esta funo novamente, s temos de
incluir o ficheiro "deck.h" e ligar ao cdigo do novo executvel o ficheiro objecto shuffle.o.
O aproveitamento do cdigo est sempre a acontecer. No escrevemos o cdigo da funo printf quando a
chammos em cima como uma declarao de depurao, O linker encontra a sua definio no ficheiro que
inclumos #include <stdlib.h> e ligao ao cdigo objecto armazenada na biblioteca C (/lib/libc.so.6).
Deste modo podemos utilizar a funo de algum que sabemos trabalhar correctamente e preocuparmonos
em resolver os nossos problemas. por este motivo que os ficheiros de cabealho s contm as definies de
dados e de funes e no o corpo das funes. Normalmente voc cria os ficheiros objecto ou bibliotecas para
5/8

o linker por no executvel. Um problema podia ocorrer com o nosso cdigo visto que no pusemos nenhum
definio no nosso ficheiro cabealho. O que que podemos fazer para ter a certeza que tudo corre sem
problemas?

Mais duas Opes Importantes


A opo Wall activa todo o tipo de avisos relativamente sintaxe da linguagem para nos ajudar a ter a
certeza que o nosso cdigo est correcto e portvel tanto quanto possvel. Quando utilizamos esta opo e
compilamos o nosso cdigo podemos ver algo como:
game.c:9: warning: implicit declaration of function `shuffle'

Isto diznos que temos mais algum trabalho a fazer. Precisamos de pr uma linha no ficheiro de cabealho,
onde diremos ao compilador tudo sobre a nossa funo shuffle assim poder fazer as verificaes que
precisa de fazer. Parece complicado, mas separa a definio da implementao e permitenos utilizar a funo
em qualquer lado bastando incluir o nosso novo ficheiro cabealho e liglo ao nosso cdigo objecto.
Introduziremos esta linha no ficheiro deck.h.
void shuffle(deck_t *pdeck);

Isto evitar a mensagem de aviso.


Uma outra opo comum do compilador a optimizao O# (ou seja O2). Isto diz ao compilador o nvel de
optimizao que quer. O compilador tem um saco cheio de truques para tornar o seu cdigo mais rpido. Para
um pequeno programa como o nosso no notaremos qualquer diferena, mas para programas grandes pode
melhorar um pouco a rapidez. Voc v esta opo em todo o lado por isso devia saber o que significa.

Depurao
Como todos sabemos, s porque o nosso cdigo compilou no quer dizer que vai trabalhar do modo que
queremos. Pode verificar que so utilizados todos os nmeros de uma s vez correndo
game | sort n | less

e vendo que no falta nada. O que que devemos fazer se houver um problema? Como que olhamos por
debaixo da madeira e encontramos o erro? Pode verificar o seu cdigo com um depurador. A maioria das
distribuies fornecem um depurador clssico, o gdb. Se a linha de comandos o atrapalha como a mim, o
KDE oferece um frontend bastante simptico, com o KDbg. Existem outros frontends, e so muito
semelhantes. Para comear a depurar, escolha File>Executable e depois encontre o seu programa, o jogo.
Quando prime F5 ou escolhe Execution>Run a partir do menu, voc devia ver uma sada numa janela
parte. O que que acontece ? No vemos nada na janela. No se preocupe, o KDbg no est a falhar. O
problema vem do facto de no termos posto nenhuma informao de depurao no executvel, assim i KDbg
no nos pode dizer o que se passa internamente. A flag do compilador g pe a informao necessria dentro
dos ficheiros objecto. Deve compilar os ficheiros objecto (extenso .o) com esta flag, assim o comando passa
a ser:
gcc g c shuffle.c game.c
gcc g o game game.o shuffle.o

6/8

Isto pe marcas no executvel que permitem ao gdb e ao KDbg saber o que est a fazer. Fazer depurao
uma tarefa importante e vale a pena o tempo gasto em aprender como o fazer correctamente. O modo como os
depuradores ajudam os programadores a habilidade de definir "pontos de paragem" no cdigo fonte. Tente
agora definir um atravs de um clique com o boto esquerdo na linha com a chamada funo shuffle.
Deve aparecer um pequeno circulo vermelho na linha seguinte. Agora, prime F5 e o programa pra a
execuo nessa linha. Prima F8 para entrar dentro da funo shuffle. Bem, estamos agora a olhar para o
cdigo a partir do ficheiro shuffle.c! Podemos controlar a execuo passo a passo e ver o que se passa. Se
deixar o apontador sobre uma varivel local, ver o valor que guarda. Aprecivel. Muito melhor que aquelas
frases com printf's, no ?

Resumo
Esta artigo apresentou uma visita clara compilao e depurao aos programas C. Discutimos os passos que
o compilador faz e as opes que devemos passar ao gcc para ele fazer esses passos. Introduzimos a ligao a
bibliotecas partilhadas e terminmos com uma introduo aos depuradores. Requer bastante trabalho para
saber realmente, o que est a fazer, mas espero que isto o ajude a comear com o p direito. Pode encontrar
mais informao nas pginas man e info acerca do gcc, as e do ld.
Escrever cdigo por si mesmo ensinalhe o mais importante. Para praticar, podia utilizar estas bases simples
do programa de jogo de cartas utilizado neste artigo e escrever um jogo de blackjack. Aproveite o tempo para
aprender a utilizar um depurador. muito mais fcil comear com um GUI como o KDbg. Se adicionar
funcionalidade aos poucos, saber as coisas sem se dar por isso. Lembrese mantenhao a correr!
Aqui esto algumas coisas que poder precisas para criar um jogo completo.
Uma definio do jogador de cartas (por exemplo podia definir o deck_t como definiu o player_t).
Uma funo que distribui um dado nmero de cartas a um dado jogador. Lembrese de incrementar o
nmero de 'distribudas' do baralho para saber de onde deve tirar a prxima carta. Lembrese de saber
o nmero de cartas que cada jogador tem na mo.
Alguma interaco dos utilizadores, para pedir se o utilizador quer outra carta.
Uma funo para apresentar as cartas de um jogador. A carta tem um valor de % 13 (a comear em 0
at 12), o naipe tem um valor de / 13 (a comear em 0 at 3).
Uma funo para determinar o valor das cartas que um utilizador tem na mo. Os ases so cartas com
um valor de zero e podem valer 1 ou 11. Os reis tm valor 10 e no mnimo 10.

Ligaes
gcc Coleco do compilador GCC da GNU
gdb O Debugger da GNU
KDbg Debugger GUI do KDE
Compilador pirata Grande compilador pirata de Ken Thompson

Webpages maintained by the LinuxFocus Editor team


Lorne Bailey
"some rights reserved" see linuxfocus.org/license/
http://www.LinuxFocus.org

7/8

Translation information:
en > : Lorne Bailey <sherm_pbody/at/yahoo.com>
en > pt: Bruno Sousa <bruno/at/linuxfocus.org>

20050110, generated by lfparser_pdf version 2.51

8/8

Вам также может понравиться