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
*/