Pré-processamento

A compilação de qualquer programa C começa com um pré-processamento que cuida das linhas do programa que começam com #.  Esse pré-processamento é realizado por um módulo do compilador conhecido como pré-processador, ou pré-compilador.

A ideia de um programa que tem dois níveis lógicos, com uma sintaxe para uma parte das linhas de código e outra sintaxe para as demais linhas, pode parecer deselegante. Mas do ponto de vista prático, ela é útil e poderosa.

Este sítio usa apenas duas diretivas (= directives) de pré-processamento: #define e #include.

Sumário:

A diretiva define

A diretiva define define uma abreviatura — conhecida como macro — para um trecho de código.  Por exemplo, a linha

#define MAX 1000

define MAX como abreviatura de 1000.  A sequência de caracteres que começa depois de MAX e vai ⚠ até o fim da linha é o significado da abreviatura, ou seja, o valor da macro.  (Se você escrever um ; no fim da linha, esse caractere fará parte da macro.)

Exemplo 1.  O programa

#define MAX 1000

int main (void) {
   int v[MAX];
   for (int i = 0; i < MAX; ++i) {
      . . .
   }
   return EXIT_SUCCESS;
} 

é transformado pelo pré-processador em

int main (void) {
   int v[1000];
   for (int i = 0; i < 1000; ++i) {
      . . .
   }
   return EXIT_SUCCESS;
} 

Exemplo 2.  Tal como uma função, uma macro pode ter parâmetros. Assim, o trecho de programa

#define troca (A, B) {int t = A; A = B; B = t;} 

for (int i = 0; i < 100; ++i) {
   int k = i;
   for (int j = i+1; j <= 100; ++j) 
      if (a[j] < a[k]) k = j;
   troca (a[i], a[k]);
} 

é transformado pelo pré-processador em

for (int i = 0; i < 100; ++i) {
   int k = i;
   for (int j = i+1; j <= 100; ++j) 
      if (a[j] < a[k]) k = j;
   {int t = a[i]; a[i] = a[k]; a[k] = t;}
} 

A diretiva include

A diretiva include acrescenta ao seu programa o conteúdo do arquivo especificado.

Exemplo 1.  Suponha que um arquivo aaa.txt no diretório corrente tem o seguinte conteúdo:

int GLOB = 8; // variável global
int func (int e); // protótipo de função

Então o programa

#include "aaa.txt"

int main (void) { 
   while (GLOB <= 64) {
      int y = func (5);
      printf ("%d\n", y);
      GLOB *= 2;
   }
   return EXIT_SUCCESS;
}

int func (int i) { // calcula GLOB^i
   . . .
}

será transformado pelo pré-processador em

int GLOB = 8;
int func (int e);

int main (void) { 
   while (GLOB <= 64) {
      int y = func (5);
      printf ("%d\n", y);
      GLOB *= 2;
   }
   return EXIT_SUCCESS;
}

int func (int i) { // calcula GLOB^i
   . . .
}

Exemplo 2.  Se o nome do arquivo a ser incluído estiver embrulhado em <> (e não em aspas duplas), o pré-processador irá procurá-lo num diretório apropriado do sistema (usualmente no diretório /usr/include/) e não no diretório corrente:

#include <aaa.txt>

int main (void) { 
   . . .
}

Isso é usado, em geral, para incluir interfaces de bibliotecas padrão no seu programa.

Exemplo 3.  O arquivo a ser incluído pode conter outros #include e #define. Nesse caso, a expansão das diretivas é recursiva.  Suponha, por exemplo, que o arquivo aaa.txt no diretório corrente consiste no seguinte:

#define PI 3.14159
#include <math.h>

Então o programa

#include "aaa.txt"

int main (void) { 
    double y = sin (PI/4);
    printf ("%f\n", y);
    return EXIT_SUCCESS;
}

será transformado pelo pré-processador em

. . .
. . .

int main (void) { 
    double y = sin (3.14159/4);
    printf ("%f\n", y);
    return EXIT_SUCCESS;
}

onde as linhas  . . .  estão no lugar do conteúdo do arquivo math.h.

A versão pré-processada de um programa

O resultado do pré-processamento de um programa é uma versão limpa do programa, sem diretivas de pré-processamento.  O programador não precisa colocar as mãos nessa versão pré-processada, pois ela será automaticamente submetida ao módulo nobre do compilador.  Entretanto, se tiver curiosidade, o programador pode examinar a versão pré-processada: a linha de comando

~$ gcc -E xxx.c > yyy.c

(note a opção -E do compilador)  submete o programa original xxx.c ao compilador e grava a versão pré-processada do programa no arquivo yyy.c.