Ferramentas do usuário

Ferramentas do site


pre_compilacao

Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.


pre_compilacao [2023/09/12 16:14] (atual) – criada - edição externa 127.0.0.1
Linha 1: Linha 1:
 +====== 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 <arquivo.h>''
 +
 +''#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'':
 +
 +<code c>
 +/* 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 <stdio.h>
 +
 +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;
 +}
 +</code>
 +
 +<code c>
 +/* programa_auxiliar_001.c */
 +
 +#include <stdio.h>
 +extern int iValor_a;
 +extern int iValor_b;
 +
 +void imprime_soma (void)
 +{
 +   printf ("Soma %d\n", iValor_a + iValor_b);
 +   return;
 +}
 +</code>
 +
 +<code c>
 +/* soma.h, utilizado por programa_principal_001.c e programa_auxiliar_001.c */
 +
 +void imprime_soma(void); /* declaracao da funcao */
 +</code>
 +
 +===== 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'')
 +
 +<code c>
 +/* programa_principal_002.c */
 +
 +#include <stdio.h>
 +
 +#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;
 +}
 +</code>
 +
 +===== Diretivas #if, #else e #endif =====
 +
 +Sintaxe:
 +<code c>
 +#if condição
 +   bloco de condição verdadeiro
 +#else
 +   bloco condição falso
 +#endif
 +</code>
 +
 +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''
 +
 +<code c>
 +/* programa_ifelseendif.c */
 +
 +#include <stdio.h>
 +#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;
 +}
 +</code>
 +
 +===== Diretivas #ifdef e #ifndef =====
 +
 +Sintaxe:
 +<code c>
 +#ifdef variável_pré_definida
 +   bloco de condição verdadeiro
 +#else
 +   bloco de condição falso
 +#endif
 +</code>
 +
 +ou
 +
 +<code c>
 +#ifndef variável_pré_definida
 +   bloco de condição verdadeiro
 +#else
 +   bloco de condição falso
 +#endif
 +</code>
 +
 +É 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''
 +
 +<code c>
 +/* programa_ifdef.c */
 +#include <stdio.h>
 +
 +#ifdef __WINDOWS__
 +   #include <strings.h> /* manipulação de strings no windows */
 +#else
 +   #ifdef __LINUX__
 +      #include <string.h>  /* 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;
 +}
 +</code>
 +
 +===== 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.
 +
 +<code c>
 +/* programa_error.c */
 +#include <stdio.h>
 +
 +#ifdef __WINDOWS__
 +   #include <strings.h> /* manipulação de strings no windows */
 +#else
 +   #ifdef __LINUX__
 +      #include <string.h>  /* 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;
 +}
 +</code>
 +
 +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.
 +<code>
 +programa_error.c:10:8: error: #error "Deve-se especificar __LINUX__ ou __WINDOWS__ na compilação"
 +</code>
 +
 +E estes erros ocorrem devido a ausência do ''header'' correto para o compilador.
 +<code>
 +programa_error.c: In function ‘main’:
 +programa_error.c:19: warning: incompatible implicit declaration of built-in function ‘strcat’
 +</code>
 +
 +===== 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.
 +
 +<code c>
 +/* programa_undef.c */
 +#include <stdio.h>
 +
 +#ifdef __WINDOWS__
 +#undef __LINUX__ /* previne em caso de erro no momento da compilação */
 +   #include <strings.h> /* manipulação de strings no windows */
 +#endif
 +
 +#ifdef __LINUX__
 +   #include <string.h>  /* 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;
 +}
 +</code>
 +
 +===== 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:
 +
 +<code c>
 +__LINE__ -> Número da linha do no arquivo fonte.
 +__FILE__ -> Nome do arquivo fonte.
 +__DATE__ -> Data da compilação.
 +__TIME__ -> Hora da compilação. 
 +</code>
 +
 +<code c>
 +#include <stdio.h>
 +
 +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;
 +}
 +</code>
 +
 +Resultado da execução depois de compilar com o comando ''gcc programa_variaveis.c -op -DDEBUG''
 +<code>
 +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
 +</code>
 +
 + --- //[[marcos@laureano.eti.br|Marcos Laureano]] 2009/05/07 14:31//