====== Pré-Compilação ====== ===== Fases de uma compilação ===== {{:fases_pre_compilacao.pdf|Fases de uma compilação}} O processo de compilação de um programa é constituído de três fases distintas: - pré-compilação; - compilação; - link-edição. Na fase de pré-compilação, o programa fonte é lido e caso se encontre comandos do pré-compilador, eles serão processados. O pré-compilador gera então um código intermediário que será lido pelo compilador. O compilador interpreta a linguagem deste fonte intermediário e gera o código objeto, que é um código em assembler, pronto para ser utilizado. Na fase de link-edição, o link-editor lê o código objeto gerado e identificam nele quais são as funções do sistema que foram utilizadas e busca o código das mesmas nas bibliotecas de sistema. Por fim o link-editor agrupa todos os códigos objetos e gera o programa executável final. ===== Diretiva #include ===== Sintaxe: ''#include '' ''#include "arquivo.h"'' ---- Todos os comandos para o pré-compilador começam com  o caractere "''#''". O comando **''#include''** indica para o pré-compilador ler o arquivo indicado e colocar o mesmo no programa fonte intermediário. O arquivo incluído possui o nome de arquivo //header// e geralmente possui protótipo de funções a serem utilizadas por todos os programas de um sistema. Possui também as declarações de tipos existentes (''typedef'') no sistema. Quando um arquivo //header// pertence ao sistema (ou seja, ao compilador) deve-se colocar o nome dele entre "''<''" e "''>''". Se o arquivo //header// for local (criado pelo programador) deve-se colocar o nome dele entre aspas. Na prática, esta regra não precisa ser seguida, pois a utilização de aspas indica ao compilador para primeiro procurar o arquivo //header// no diretório local e depois nos diretórios do sistema, e o ''<'' ''>'' indica para o compilador para primeiro procurar o arquivo //header// nos diretórios do sistema e depois no diretório local. Veja os programas ''principal'', ''auxiliar'' e o arquivo //header// ''soma.h'': /* programa_principal_001.c */ /* Repare na forma como os arquivos headers foram inseridos. O arquivo header padrão do sistema tem o seu nome * preenchido entre < > e o arquivo header local tem o seu nome preenchido entre “ “. */ #include "soma.h" #include int iValor_a; int iValor_b; int main (void) { int iResultado; printf ("Entre com os valores:"); scanf ("%d %d", &iValor_a, &iValor_b); imprime_soma(); /* esta funca esta declarada no arquivo soma.h */ return 0; } /* programa_auxiliar_001.c */ #include extern int iValor_a; extern int iValor_b; void imprime_soma (void) { printf ("Soma %d\n", iValor_a + iValor_b); return; } /* soma.h, utilizado por programa_principal_001.c e programa_auxiliar_001.c */ void imprime_soma(void); /* declaracao da funcao */ ===== Diretiva #define ===== Sintaxe: ''#define nome_constante valor_constante'' ---- É possível definir [[variavel_definicao|variáveis]] para o pré-compilador, fazendo com que ele atribua um valor a uma [[variavel_definicao|variável]]. Sendo importante ressaltar é que esta constante é uma [[variavel_definicao|variável]] do pré-compilador e não do programa. Cada vez que o pré-compilador encontrar esta [[variavel_definicao|variável]], a mesma é substituída pelo conteúdo definido anteriormente, não levando em consideração o contexto de compilação. **Ressaltando que a definição de uma [[variavel_definicao|variável]] de pré-compilação é pura substituição de caracteres.** Veja o exemplo: (compile para ver a diferença: ''gcc programa_principal_002.c -E'') /* programa_principal_002.c */ #include #define VALOR_MAGICO 27 int main (void) { int iValor; while (1) { printf ("Entre com o valor:"); scanf ("%d", &iValor); if (iValor == VALOR_MAGICO) { break; } } return 0; } ===== Diretivas #if, #else e #endif ===== Sintaxe: #if condição bloco de condição verdadeiro #else bloco condição falso #endif Em certos casos é preciso selecionar um trecho de um código de acordo com uma [[comandos_selecao|condição]] pré-estabelecida, de forma que se compile ou não um trecho do código. Esta técnica, chamada compilação condicional, é muito usada quando se tem um programa que será usado em diversas plataformas (Linux, Windows, etc) e somente um pequeno trecho de programa difere de um sistema para outro. Como é extremamente desejável que se tenha um único código, simplificando assim a manutenção e evitando riscos de alterar em um sistema e esquecer de se alterar em outro, utiliza-se à compilação condicional nos trechos diferentes. Pode-se [[comandos_selecao|selecionar]] somente um trecho com o ''**#if**'' ou selecionar entre dois trechos com o ''**#if...#else..**'' O final do trecho em qualquer um dos casos é delimitado pela diretiva ''**#endif**''. Para finalizar, ressalta-se que o ''**#if**'' só será executado se na fase de pré-compilação for possível resolver a expressão condicional colocada. Portanto não é possível se fazer compilação condicional baseada em valores de [[[[variavel_definicao|variáveis]] da Linguagem C, pois o valor da [[variavel_definicao|variável]] só estará disponível quando o programa for executado e não durante a compilação. A [[variavel_definicao|variável]] do teste pode ser definida internamente ou ser diretamente definida quando se chama o comando de compilação, tornando dinâmico o processo. Para se definir um [[tipos_dados|valor]] para uma [[variavel_definicao|variável]] ao nível de comando de compilação deve-se usar a opção abaixo: ''gcc progxx.c –Dvar=valor –o progxx'' /* programa_ifelseendif.c */ #include #define PULA 1 int main (void) { int i; for(i=1; i < 30; i++) { #if PULA == 1 if (i > 10 && i < 20) /* este if estará disponível para o compilação somente se o valor de PULA for igual a 1 */ { continue; } #endif printf ("%d\n", i); } return 0; } ===== Diretivas #ifdef e #ifndef ===== Sintaxe: #ifdef variável_pré_definida bloco de condição verdadeiro #else bloco de condição falso #endif ou #ifndef variável_pré_definida bloco de condição verdadeiro #else bloco de condição falso #endif É possível implementar a compilação condicional baseada na //existência// de uma [[variavel_definicao|variável]] e não em seu conteúdo. Para isto é utilizado a diretiva ''**#ifdef**''. Quando a [[variavel_definicao|variável]] especificada estiver definida, o trecho entre o ''**#ifdef**'' e o ''**#endif**'' será compilado, caso contrário, não. Pode-se definir a [[variavel_definicao|variável]] no momento da compilação evitando assim a alteração de código quando da geração de versões diferentes. Usar a seguinte sintaxe para se fazer isto: ''gcc progxx.c –Dvariavel –o progxx'' /* programa_ifdef.c */ #include #ifdef __WINDOWS__ #include /* manipulação de strings no windows */ #else #ifdef __LINUX__ #include /* manipulação de strings no linux */ #else #error "Deve-se especificar __LINUX__ ou __WINDOWS__ na compilação" #endif #endif int main(void) { char sFrase[50] = "Alo mundo ", sNome[20]; printf("\nEntre com um nome:"); scanf("%s", sNome); strcat( sFrase, sNome); printf("\n%s", sFrase); return 0; } ===== Diretiva #error ===== Sintaxe: ''#error mensagem'' ---- Esta diretiva deve ser usada quando se quer **exigir** a definição de uma ou outra [[variavel_definicao|variável]] ao nível de compilação ou internamente no programa. /* programa_error.c */ #include #ifdef __WINDOWS__ #include /* manipulação de strings no windows */ #else #ifdef __LINUX__ #include /* manipulação de strings no linux */ #else #error "Deve-se especificar __LINUX__ ou __WINDOWS__ na compilação" /* Esta mensagem só aparecerá em caso de erro */ #endif #endif int main(void) { char sFrase[50] = "Alo mundo ", sNome[20]; printf("\nEntre com um nome:"); scanf("%s", sNome); strcat( sFrase, sNome); printf("\n%s", sFrase); return 0; } Erro que ocorre no momento da compilação. Comando utilizado: ''**gcc programa_error.c -op**'' Este erro ocorreu devido a falta da diretiva no momento da compilação. programa_error.c:10:8: error: #error "Deve-se especificar __LINUX__ ou __WINDOWS__ na compilação" E estes erros ocorrem devido a ausência do ''header'' correto para o compilador. programa_error.c: In function ‘main’: programa_error.c:19: warning: incompatible implicit declaration of built-in function ‘strcat’ ===== Diretiva #undef ===== Sintaxe: ''#undef variável_pré_definida'' ---- Na construção de dependências pode-se ter uma situação que seja necessária desabilitar alguma [[variavel_definicao|variável]] de pré-compilação, mesmo que ela seja definida no momento da compilação. Para isto é utilizada a diretiva ''**#undef**'', que irá retirar a definição da variável especificada. /* programa_undef.c */ #include #ifdef __WINDOWS__ #undef __LINUX__ /* previne em caso de erro no momento da compilação */ #include /* manipulação de strings no windows */ #endif #ifdef __LINUX__ #include /* manipulação de strings no linux */ #endif int main(void) { char sFrase[50] = "Alo mundo ", sNome[20]; printf("\nEntre com um nome:"); scanf("%s", sNome); strcat( sFrase, sNome); printf("\n%s", sFrase); return 0; } ===== Variáveis pré-definidas ===== O pré-compilador disponibiliza uma série de [[variavel_definicao|variáveis]] de pré-compilação para serem utilizadas no programa. Essas variáveis geralmente são utilizadas para código de ''debug'' ou ''log'' a ser gerado por programas. São elas: __LINE__ -> Número da linha do no arquivo fonte. __FILE__ -> Nome do arquivo fonte. __DATE__ -> Data da compilação. __TIME__ -> Hora da compilação. #include int main (void) { int i; #ifdef DEBUG /* __FILE__ sempre terá o nome do programa fonte original, mesmo que o executável printf("\nInicio do programa %s\n", __FILE__); tenha outro nome */ printf("\nVersao de %s-%s\n", __DATE__, __TIME__); /* data e hora da última compilação */ #endif for (i=1; i < 10; i++) { printf ("%d\n", i); } #ifdef DEBUG /* durante o pré-processamento, __LINE__ será substituída pela linha correspondente */ printf("\nA contagem parou! Estamos na linha %d\n", __LINE__); #endif printf("\nFim da execução\n"); #ifdef DEBUG printf("\nA última linha do programa é: %d\n", __LINE__); #endif return 0; } Resultado da execução depois de compilar com o comando ''gcc programa_variaveis.c -op -DDEBUG'' Versao de May 7 2009-18:22:48 1 2 3 4 5 6 7 8 9 A contagem parou! Estamos na linha 20 Fim da execução A última linha do programa é: 26 --- //[[marcos@laureano.eti.br|Marcos Laureano]] 2009/05/07 14:31//