Recentemente enquanto assistia a um vídeo do Tsoding(em inglês) fui apresentado a uma técnica extremamente útil e relativamente simples para geração código a partir de uma lista de dados. A técnica chamada de “X macro” utiliza o pré-processador do C e C++ para criar uma lista de macros a ser definida no momento da utilização. Por exemplo, suponha-se que seja necessária uma lista fixa de arquivos que precisam ser utilizados pela aplicação. Inicialmente cria-se uma macro que define uma lista de utilizações de uma outra macro X que ainda não foi definida:
Esta macro não pode ser utilizada enquanto a macro X não for definida. A definição fica a cargo da utilização em um contexto específico. O nome X é só uma convenção, pode ser qualquer coisa desde que seja o mesmo nome para todos os valores definidos.
O exemplo seguinte imprime os nomes dos arquivos no console:
#define X(nome) printf("- " nome "\n"); LISTA_ARQUIVOS #undef X
Na primeira linha é definida uma macro X que imprime no console uma linha com valor passado precedido de "- ". A segunda linha expande a macro original substituindo cada linha pelo que foi definido na macro X. Por último, a macro X é “desdefinida” para que possa ser utilizada novamente em outro lugar. O código acima gera a seguinte linha:
intmain() { printf("Arquivos a serem carregados:\n");
#define X(nome) printf("- " nome "\n"); LISTA_ARQUIVOS #undef X
return0; }
que imprime isso no console:
Arquivos a serem carregados: - C:\\Users\juninho-pimpao\Documents\arquivo1.txt - C:\\Users\juninho-pimpao\Documents\arquivo2.txt - C:\\Users\juninho-pimpao\Documents\arquivo3.txt
O que pode ser feito fica a cargo da imaginação do programador e dos limites do pré-processador. O código a seguir complementa o anterior imprimindo também o conteúdo dos arquivos:
O código acima não vai compilar pois as funções carrega_textura e destroi_textura não foram definidas.
O pré-processador também vai substituir as chamadas as utilizações da macro NULL e #include <stdlib.h>, porém estas alterações foram omitidas para melhoras a legibilidade.
No exemplo a quantidade código gerado é semelhante que à utilizada na geração, mas é preciso lembrar que em uma aplicação real a quantidade de arquivos a ser carregada provavelmente seria muito maior. Além disso, a quantidade de código duplicado é reduzida, reduzindo também a possibilidade de erros de digitação e de “copia e cola”.