- Pré-processador C – Parte 1
- Pré-processador C: Compilação condicional – Parte 2
- Pré-processador C: Diagnóstico – Parte 3
- Pré-processador C: X macros – Parte 4
Olá, caro leitor! Continuando o assunto sobre o pré-processador C, vamos discutir neste artigo alguns recursos utilizados para realizar diagnóstico durante o processo de compilação e execução de um programa. Vamos lá!
Macros Predefinidas para Diagnóstico
O padrão C ANSI possui algumas macro predefinidas que podem ser utilizadas na codificação. Cabe ressaltar que o próprio compilador pode definir algumas macros. As macros predefinidas são:
__LINE__
É um número inteiro que representa a linha atual do arquivo que está sendo compilado.
__FILE__
É uma string que representa o nome do arquivo que está sendo compilado.
__DATE__
É uma string que representa a data (formato “Mmm dd yyyy”) em que o arquivo foi compilado.
__TIME__
É uma string que representa o horário (formato “hh:mm:ss”) em que o arquivo foi compilado.
__STDC__
É um número inteiro que indica se o compilador segue o padrão C ANSI. Se o valor é igual à constante decimal 1 então o compilador segue o padrão C ANSI, caso contrário o compilador segue outro padrão.
Controle de linha
A diretiva #line é utilizada para indicar ao pré-processador qual o número da linha que está sendo processada. Essa diretiva pode ser utilizada para prover uma informação mais detalhada do processo de compilação/depuração, oferecendo diagnóstico durante essa fase.
Quando essa diretiva é utilizada, o conteúdo das macros __LINE__ e __FILE__ são alteradas conforme o contexto. Essa diretiva pode ser utilizada de duas maneiras, sendo sua forma geral:
1 |
#line <num> <”arquivo”> |
O nome do arquivo é um parâmetro opcional. Considere, por exemplo, o código abaixo:
1 2 3 4 5 6 7 8 9 10 |
#line 300 void Test(void * ptrData) //300 { //301 if(ptrData == NULL) //302 { //303 printf("[%s - linha: %i]Ponteiro NULL!", __FILE__, __LINE__);//304 } /*.....*/ } |
A declaração de
1 |
#line 300 |
determina que a contagem de linha é iniciada com o valor 300. No exemplo as macros __FILE__ e __LINE__ são utilizadas para formatar uma mensagem com detalhes da linha e do arquivo em que a operação é executada.
Instruções para o compilador
Para instruir o compilador a diretiva #pragma pode ser utilizada. As instruções que podem ser utilizadas estão diretamente relacionadas com o compilador, sendo necessário consultar o seu manual para verificar os argumentos e instruções disponibilizados. A sua forma geral é:
1 |
#pragma <string> |
A <string> representa a instrução e os argumentos informados.
Por exemplo, no compilador GCC temos a instrução message, que é responsável por exibir uma mensagem durante o processo de compilação.
1 2 3 4 5 6 7 8 9 10 |
void Test(void * ptrData) { #pragma message "Função Test: " __FILE__ if(ptrData == NULL) { printf("[%s - linha: %i]Ponteiro NULL!", __FILE__, __LINE__); } /*.....*/ } |
Diagnóstico
Uma macro muito utilizada no processo de depuração é definida na biblioteca C padrão ASSERT.h. A macro é chamada de assert e tem como função testar se uma determinada condição é verdadeira, caso contrário o programa é encerrado.
1 2 3 4 5 6 |
void Test(void * ptrData) { assert(ptrData != NULL); /*.....*/ } |
No exemplo, se a condição testada é falsa o programa será encerrado com a seguinte mensagem:
1 |
Assertion failed: ptrData != NULL, file <arquivo>, line <número da linha> |
Esses testes são úteis durante a depuração de um programa justamente para diagnóstico de possíveis falhas de execução devido a um estado inválido do programa, para isso a macro pode ser definida ou removida conforme o símbolo NDEBUG. Se a macro NDEBUG for definida então a macro assert() será ignorada e não terá efeito no programa.
Conclusão
Neste artigo foram apresentados, de maneira introdutória, alguns recursos do pré-processador que auxiliam o processo de depuração de aplicações e de diagnóstico de erros. Como foi demonstrado, com a utilização das asserções é possível verificar o estado de uma aplicação durante sua execução tornando-se uma ferramenta importante para encontrar bugs. Outra forma de diagnóstico pode ser realizada durante o processo de compilação, uma vez que as diretivas intrínsecas do pré-processador apresentam informações desse processo.
Na quarta parte deste artigo será apresentada uma técnica de expansão de macros chamada X macros.
Referências
[1] Livro: C, completo e total – 3ª edição revista e atualizada. Herbert Schildt.
Muito bom!
Obrigado, André!