C - Pré-processadores

o C Preprocessornão faz parte do compilador, mas é uma etapa separada no processo de compilação. Em termos simples, um pré-processador C é apenas uma ferramenta de substituição de texto e instrui o compilador a fazer o pré-processamento necessário antes da compilação real. Vamos nos referir ao pré-processador C como CPP.

Todos os comandos do pré-processador começam com um símbolo hash (#). Deve ser o primeiro caractere não vazio e, para facilitar a leitura, uma diretiva do pré-processador deve começar na primeira coluna. A seção a seguir lista todas as diretivas importantes do pré-processador -

Sr. Não. Diretriz e descrição
1

#define

Substitui uma macro de pré-processador.

2

#include

Insere um cabeçalho específico de outro arquivo.

3

#undef

Cancela a definição de uma macro de pré-processador.

4

#ifdef

Retorna verdadeiro se esta macro for definida.

5

#ifndef

Retorna verdadeiro se esta macro não for definida.

6

#if

Testa se uma condição de tempo de compilação é verdadeira.

7

#else

A alternativa para #if.

8

#elif

#else e #if em uma instrução.

9

#endif

Termina o pré-processador condicional.

10

#error

Imprime mensagem de erro em stderr.

11

#pragma

Emite comandos especiais para o compilador, usando um método padronizado.

Exemplos de pré-processadores

Analise os exemplos a seguir para entender as várias diretivas.

#define MAX_ARRAY_LENGTH 20

Esta diretiva diz ao CPP para substituir as instâncias de MAX_ARRAY_LENGTH por 20. Use #define para constantes para aumentar a legibilidade.

#include <stdio.h>
#include "myheader.h"

Estas diretivas dizem ao CPP para obter stdio.h de System Librariese adicione o texto ao arquivo de origem atual. A próxima linha diz ao CPP para obtermyheader.h do diretório local e adicione o conteúdo ao arquivo de origem atual.

#undef  FILE_SIZE
#define FILE_SIZE 42

Diz ao CPP para indefinir FILE_SIZE existente e defini-lo como 42.

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

Diz ao CPP para definir MESSAGE apenas se MESSAGE ainda não estiver definida.

#ifdef DEBUG
   /* Your debugging statements here */
#endif

Diz ao CPP para processar as instruções incluídas se DEBUG estiver definido. Isso é útil se você passar o sinalizador -DDEBUG para o compilador gcc no momento da compilação. Isso definirá DEBUG, para que você possa ativar e desativar a depuração durante a compilação.

Macros Predefinidas

ANSI C define várias macros. Embora cada um esteja disponível para uso na programação, as macros predefinidas não devem ser modificadas diretamente.

Sr. Não. Macro e descrição
1

__DATE__

A data atual como um literal de caractere no formato "MMM DD AAAA".

2

__TIME__

A hora atual como um literal de caractere no formato "HH: MM: SS".

3

__FILE__

Contém o nome do arquivo atual como um literal de string.

4

__LINE__

Contém o número da linha atual como uma constante decimal.

5

__STDC__

Definido como 1 quando o compilador está em conformidade com o padrão ANSI.

Vamos tentar o seguinte exemplo -

#include <stdio.h>

int main() {

   printf("File :%s\n", __FILE__ );
   printf("Date :%s\n", __DATE__ );
   printf("Time :%s\n", __TIME__ );
   printf("Line :%d\n", __LINE__ );
   printf("ANSI :%d\n", __STDC__ );

}

Quando o código acima em um arquivo test.c é compilado e executado, ele produz o seguinte resultado -

File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1

Operadores de pré-processador

O pré-processador C oferece os seguintes operadores para ajudar a criar macros -

O operador de continuação de macro (\)

Uma macro é normalmente confinada a uma única linha. O operador de continuação de macro (\) é usado para continuar uma macro que é muito longa para uma única linha. Por exemplo -

#define  message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

O operador Stringize (#)

O operador stringize ou sinal numérico ('#'), quando usado em uma definição de macro, converte um parâmetro de macro em uma constante de string. Este operador pode ser usado apenas em uma macro com um argumento ou lista de parâmetros especificada. Por exemplo -

#include <stdio.h>

#define  message_for(a, b)  \
   printf(#a " and " #b ": We love you!\n")

int main(void) {
   message_for(Carole, Debra);
   return 0;
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Carole and Debra: We love you!

O operador Token Colando (##)

O operador de colagem de token (##) em uma definição de macro combina dois argumentos. Ele permite que dois tokens separados na definição da macro sejam unidos em um único token. Por exemplo -

#include <stdio.h>

#define tokenpaster(n) printf ("token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   tokenpaster(34);
   return 0;
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

token34 = 40

Aconteceu porque este exemplo resulta na seguinte saída real do pré-processador -

printf ("token34 = %d", token34);

Este exemplo mostra a concatenação do token ## n no token34 e aqui usamos ambos stringize e token-pasting.

O operador definido ()

O pré-processador definedoperador é usado em expressões constantes para determinar se um identificador é definido usando #define. Se o identificador especificado for definido, o valor é verdadeiro (diferente de zero). Se o símbolo não estiver definido, o valor é falso (zero). O operador definido é especificado da seguinte forma -

#include <stdio.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   printf("Here is the message: %s\n", MESSAGE);  
   return 0;
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Here is the message: You wish!

Macros Parametrizadas

Uma das funções poderosas do CPP é a capacidade de simular funções usando macros parametrizadas. Por exemplo, podemos ter algum código para elevar ao quadrado um número da seguinte forma -

int square(int x) {
   return x * x;
}

Podemos reescrever o código acima usando uma macro da seguinte maneira -

#define square(x) ((x) * (x))

Macros com argumentos devem ser definidos usando o #defineantes que eles possam ser usados. A lista de argumentos está entre parênteses e deve seguir imediatamente o nome da macro. Espaços não são permitidos entre o nome da macro e os parênteses de abertura. Por exemplo -

#include <stdio.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void) {
   printf("Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

Max between 20 and 10 is 20