Clique sobre os tópicos listados abaixo para navegar até o conteúdo desejado.

  1. Entender macros
  2. Tipos de macro
  3. Macro vs Função
  4. Operador ##

A diretiva #define nos permite a criação de definições mais complexas em que seu conteúdo, é possível utilizar variáveis, funções e expressões na declaração de seu corpo. Não há verificação de tipos de dados em expressões no corpo de macros.

Exemplo 1
#include <stdio.h>

#define ADICAO(p, q) (p) + (q) //função definida como macro.

void main()
{
    int a = ADICAO(1,2); //o corpo
    printf("%u \n",a);
    printf("%i",ADICAO(2,2));
}
Saída
3
4 

A linguagem C suporta os quatro "tipos" básicos de macros : tipo objeto, cascata , multilinha e função. Nesta parte do tutorial vamos aprender sobre esses tipos e ver exemplos.

Tab. 1: Tipos de macros
Tipo Descrição
Objeto Define uma macro com valor
Cascata Define uma macro contendo macros
Multilinha Define uma macro com várias linhas
Função Definie uma macro em forma de função

Na macro tipo-objeto, declaramos uma macro com um nome e atribuímos um valor a macro utilizando a sintaxe abaixo.

Sintaxe
#define NOME_MACRO valor_macro
Exemplo 1
#include <iostream>
using namespace std;

#define MINHA_MACRO 2

int main()
{
    cout<< "macro:" << MINHA_MACRO;
    return 0;
}
Saída
macro:2

Na macro em cascata, declaramos uma macro com um nome e atribuímos um valor a macro e reutilizamos essa mesma macro como parte de uma nova macro.

Sintaxe
#define NOME_MACRO1 valor_macro1

#define NOME_MACRO2 expressao_contendo_NOME_MACRO1
Exemplo 2
#include <iostream>
using namespace std;

#define MINHA_MACRO 2
#define MINHA_MACRO2 MINHA_MACRO*2

int main()
{
    cout<< "macro:" << MINHA_MACRO2;
    return 0;
}
Saída
macro:4

A macro um múltiplas linhas possui as mesmas características das anteriores. Para declararmos o corpo da macro utilizamos mais de uma linha, fazemos uso de (\) como quebra de linha. Essa quebra é descartada pelo compilador.

Sintaxe
#define nome_macro \
expressao1 \
expressao2 \
expressao3 \
Exemplo 3
#include <iostream>
using namespace std;

#define TEXTO \
"uma \
string \
qualquer"
        
int main()
{
    cout<< "macro:" << TEXTO;
    return 0;
}
Saída
macro:uma string qualquer

No tipo função, a macro é declarada como uma função que possui parâmetros. Pode ser declarada como multilinha. Caso não haja parâmetros, a macro atua como multilinha.

Sintaxe
NOME_MACRO( param1, param2, paramN) \
expressao1 \
expressaoN 

Os parâmentros são utilizados nos corpos das expressões. Essas podem ser expressões aritméticas, relacionais e chamadas de funções.

Exemplo 4
#include <iostream>
using namespace std;

#define ADICAO(p, q) \
        (p) + (q)
        
int main()
{
    cout<< "macro:" << ADICAO(2,2);
    return 0;
}
Saída
macro:4

Quando aprendemos sobre macros e funções, é comum existir uma dúvida natural entre a diferença entre ambas. Para para sanar algumas dúvidas sobre macros e funções, vamos utilizar a tabela básica comparativa abaixo:

Tab 2: Macro vs Função
Macro Função
Pré-processada Compilada
Não há checagem de tipo Há checagem de tipo
Aumentam o tamanho do programa Não há alteração no tamanho do programa
Mais velocidade na execução Menos velocidade na execução
Não há checagem de erros ao compilar Há checagem de erros ao compilar

A escolha por função ou macro irá depender da aplicação. Os itens listados acima podem ser utilizados para a tomada de decisão, porém é de responsabilidade do desenvolvedor.

O operador ##, utilizado na definição de macros, nos possibilita a substituição de símbolos ou tokens em declarações de código em seu corpo.

Sintaxe
#define NOME_MACRO( parametro1, parametro2 ) parametro1##parametro2
Exemplo
//main.c
#define MINHA_MACRO(parametro1,parametro2) \
int var_##parametro1=parametro2

No exemplo de uso acima, criamos uma variável int em que seu nome é composto dos termos var_ e ##parametro1 cujos argumentos parametro1 e parametro2 foram passados.

Exemplo 1
#include <stdio.h>

#define MINHA_MACRO(parametro1, parametro2) \
        int var_##parametro1=parametro2

void main()
{
    MINHA_MACRO( teste, 999);
    printf("%i",var_teste);
}
Saída
999

No exemplo acima, o argumento teste foi substituído pelo operador ##parametro1, e o segundo argumento, 999, foi substituído por parametro2 criando assim a declaração da variável abaixo:

int var_teste = 999;

É importante observar que não criamos a variável var_teste previamente, e que a mesma foi criada como o tipo int, porém, podemos modificar a macro acima para criar variáveis de outros tipos:

Exemplo 2
#include <stdio.h>
#define MINHA_MACRO(tipo_var , nome_var, valor_var) \
        tipo_var var_##nome_var=valor_var

void main()
{
    MINHA_MACRO( unsigned short,inteira, 999);
    printf("%i\n",var_inteira);
    MINHA_MACRO( float,decimal, 10.09);
    printf("%.02f",var_decimal);
}
Saída
999
10.09

O operador ## também pode ser utilizado em conjunto com funções de forma a criarmos uma codificação de chamada genérica baseada em um valor passado como argumento:

Exemplo 3
#include <stdio.h>
void funcao1(void)
{
    printf("funcao1\n");
}
void funcao2(void)
{
    printf("funcao2\n");
}
#define EXECUTA_FUNCAO(numero_funcao)\
        funcao##numero_funcao()

void main()
{
    EXECUTA_FUNCAO(1);
    EXECUTA_FUNCAO(2);
}
Saída
funcao1
funcao2

No exemplo acima, não podemos usar variáveis, constantes e enumeradores como valor do argumento numero_funcao, sendo apenas valores inteiros.

O uso do ## leva em consideração a necessidade e também da criatividade de quem está codificando, mostrando-se um recurso significativo para criação macros mais complexas.

  1. 04/09/2025 - revisão 5 - Ajustes: pontuais, sintaxes e objetivos
  2. 11/03/2025 - revisão 4 - Correção em intro macro
  3. 07/10/2024 - revisão 3 - Adição de tipos de macros; ajustes pontuais
  4. 30/08/2024 - revisão 2 - Correção em links de objetivos
  5. 29/09/2023 - revisão 1 - Correção em referências, erros gramaticais e exemplos
  6. 19/05/2023 - versão inicial