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

  1. Entender a sobre macro
  2. Entender os tipos de macro
  3. Macro vs Função
  4. Entender o operador ##

A diretiva #define nos permite a criação de macros mais complexas em que seu conteúdo, sendo 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 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 utilizamos essa mesma macro como parte de uma nova macro.

Sintaxe
#define NOME_MACRO1 valor_macro
#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 usando (\) 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 em multilinha. Caso não haja parâmetros, a macro atua como multilinha.

Sintaxe
NOME_MACRO(param1, param2, paramN)
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 comparativa abaixo:

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 desenvolvida. 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 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 do termo var_ e ##parametro1 cujos argumentos parametro1 e parametro2 são passados como argumento.

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 observarmos 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, baseado 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. 11/03/2025 - revisão 4 - Correção em intro macro
  2. 07/10/2024 - revisão 3 - Adição de tipos de macros; ajustes pontuais
  3. 30/08/2024 - revisão 2 - Correção em links de objetivos
  4. 29/09/2023 - revisão 1 - Correção em referências, erros gramaticais e exemplos
  5. 19/05/2023 - versão inicial