Substituição de Macro (#define, #undef)

As diretivas do pré-processador são usadas ​​pelo do compilador para pré-processamento do código fonte antes de sua compilação. A diretiva sempre começa com o # (jogo da velha), por isso o compilador proíbe o uso deste símbolo nos nomes das variáveis, funções, etc.

Cada diretiva é descrita por um registro separado e opera antes da mudança de linha. Não se podem utilizar várias diretivas num só registro. Se o registro da diretiva for muito grande, ele pode ser dividido em várias linhas usando a barra invertida '\', neste caso, a próxima linha é considerada uma continuação do registro da diretiva.

A diretiva #define pode ser usada para atribuir nomes mnemônicos a constantes. Existem duas formas:

#define identificador expressão                 // forma sem parâmetro
#define identificador(par1,... par8) expressão  // forma paramétrica

A diretiva #define substitui em expressão todas as entradas encontradas adiante do identificador no texto fonte. O identificador é substituído somente se ele é um símbolo (token) separado. O identificador não é substituído se ele é parte de um comentário, parte de uma string, ou parte de um outro identificador mais longo.

O identificador de constante é governado pelas mesmas regras de nomes de variáveis. O valor pode ser de qualquer tipo:

#define ABC               100
#define PI                3.14
#define COMPANY_NAME      "MetaQuotes Software Corp."
...
void ShowCopyright()
  {
   Print("Copyright  2001-2009, ",COMPANY_NAME);
   Print("https://www.metaquotes.net");
  }

Uma expressão pode consistir de vários símbolos (tokens), tais como palavras chave, constantes, expressões constantes e não-constantes. Uma expressão termina com o fim da linha e não pode ser transferida para a próxima linha.

Exemplo:

#define TWO        2
#define THREE      3
#define INCOMPLETE TWO+THREE
#define COMPLETE  (TWO+THREE)
void OnStart()
  {
   Print("2 + 3*2 = ",INCOMPLETE*2);
   Print("(2 + 3)*2 = ",COMPLETE*2);
  }
// Resultado
// 2 + 3*2 = 8
// (2 + 3)*2 = 10

 

Forma paramétrica do #define

Na forma paramétrica, todas as subseqüentes entradas encontradas do identificador serão substituídas pela expressão levando em conta os respectivos parâmetros. Por exemplo:

 // exemplo com dois parâmetros a e b
#define A 2+3
#define B 5-1
#define MUL(a, b) ((a)*(b))
 
double c=MUL(A,B);
Print("c=",c);
/*
expressão double c=MUL(A,B);
é equivalente a double c=((2+3)*(5-1));
*/
// Resultado
// c=20

Se assegure de colocar os parâmetros entre parênteses ao usar os parâmetros na expressão, uma vez que isso ajudará a evitar erros não óbvios que são difíceis de encontrar. Se reescrevermos o código sem o uso de parêntesis, o resultado será diferente:

 // exemplo com dois parâmetros a e b
#define A 2+3
#define B 5-1
#define MUL(a, b) a*b
 
double c=MUL(A,B);
Print("c=",c);
/*
expressão double c=MUL(A,B);
é equivalente a double c=2+3*5-1;
*/
// Resultado
// c=16

Ao usar a forma paramétrica, são permitidos no máximo 8 parâmetros.

 // forma paramétrica correta
#define LOG(text)  Print(__FILE__,"(",__LINE__,") :",text)   // um parâmetro - 'text'
 
 // forma paramétrica incorreta        
#define WRONG_DEF(p1, p2, p3, p4, p5, p6, p7, p8, p9)   p1+p2+p3+p4 // mais do que 8 parâmetros a partir de p1 para p9 

 

The #undef directive

The #undef directive cancels declaration of the macro substitution, defined before.

Example:

#define MACRO
 
void func1()
  {
#ifdef MACRO
   Print("MACRO is defined in ",__FUNCTION__);   
#else
   Print("MACRO is not defined in ",__FUNCTION__);
#endif
  }
 
#undef MACRO
 
void func2()
  {
#ifdef MACRO
   Print("MACRO is defined in ",__FUNCTION__);
#else
   Print("MACRO is not defined in ",__FUNCTION__);
#endif
  }
 
void OnStart()
  {
   func1();
   func2();
  }
 
/* Resultado:
 MACRO is defined in func1
 MACRO is not defined in func2
*/

Também Veja

Identificador, Constantes de Caractere