Pré-processador C: Compilação condicional – Parte 2

Confira neste artigo no funciona a compilação condicional no Pré-processador C. É a segunda parte da série "Pré-processador C".
funções X macros compilação condicional Diagnóstico
Este post faz parte da série Pré-processador C. Leia também os outros posts da série:

Olá, caro leitor! Continuando o assunto sobre o pré-processador C, vamos discutir neste artigo os recursos de compilação condicional. Vamos lá!

Compilação condicional if-else do pré-processador

Um recurso poderoso do pré-processador C é o de compilação condicional. Você certamente já se deparou com alguma dessas diretivas de compilação condicional:

Essas diretivas instruem o pré-processador C se um determinado trecho de código deve ser compilado ou não, sendo esta condição avaliada conforme uma expressão condicional.

Utilizando a estrutura de decisão

A forma geral da estrutura de decisão é: 

Toda estrutura de decisão deve ser finalizada por #endif. A cláusula #else é utilizada da mesma maneira que na linguagem C, fornecendo alternativa caso a condição testada seja falsa.

Ao estruturar o código com expressões condicionais, o código final dependerá das condições avaliadas durante o pré-processamento. Convém observar que expressões avaliadas devem ser constantes e somente os comandos e instruções que fazem parte de uma condição verdadeira serão compilados.

As estruturas de decisão também podem ser aninhadas como o exemplo abaixo: 

Apresentadas as diretivas vamos para algumas aplicações!

Verificação de macros

O pré-processador fornece algumas diretivas e operadores que permitem verificar se uma macro já foi definida. As diretivas #ifdef e #ifndef podem ser utilizadas para esse fim. Veja:

Outra forma de fazer esse procedimento é utilizando o operador defined, ou ainda utilizando a negação !defined (#ifndef):

Considere o exemplo abaixo, no qual a macro DEBUG é utilizada na verificação condicional: 

Esse programa utiliza a macro DEBUG para definir qual mensagem será exibida no início da aplicação. Cabe frisar que a avaliação das expressões condicionais são realizadas em tempo de compilação! Assim o programa final contém apenas uma das chamadas para a função printf().

Se a macro DEBUG for definida, o código final será: 

Caso contrário: 

Header Guards

Vimos no artigo anterior, Pré-processador C – Parte 1, que a diretiva #include instrui o compilador a ler e processar um arquivo-fonte. Especificamente o conteúdo do arquivo incluído é copiado para linha onde a diretiva foi declarada.

Para exemplificar, considere um arquivo timer.h, o qual define uma struct chamada timer

E que em um determinado arquivo a biblioteca timer.h é incluída duas vezes. 

Consequentemente o conteúdo de timer.h será copiado duas vezes conforme mostra o código abaixo: 

Nesse caso, o processo de compilação será encerrado devido à duplicação da struct timer. Para evitar esses e outros erros que podem ocorrer com a inclusão de arquivos, adicionamos uma estrutura condicional chamada Header Guards.

Basicamente esse mecanismo utiliza uma macro para verificar se o arquivo já foi incluído. Uma prática comum é utilizar o nome do arquivo na macro que será definida.

Alterando o arquivo timer.h

Agora, quando o arquivo é incluído, ocorre a verificação da macro TIMER_H_INCLUDED. Se for a primeira vez que o arquivo é incluído, então a macro TIMER_H_INCLUDED será definida.

O mesmo exemplo de dupla inclusão agora com Header Guards é mostrado abaixo: 

Nesse caso o código seria compilado corretamente, pois no primeiro #include a macro ainda não foi definida. No segundo #include a macro já foi definida e a condição de teste será falsa. Assim, se timer.h for incluído em mais de um arquivo, ele será “processado” somente uma vez.

Inclusão condicional

A compilação condicional também é muito utilizada no desenvolvimento de frameworks onde arquivos-fonte podem ser compilados para diferentes plataformas. Dessa forma os arquivos incluídos no processo de compilação dependem de alguma configuração previamente definida no projeto. No exemplo abaixo os arquivos que são incluídos na compilação dependem do valor definido na macro DEVICE. 

Esse mecanismo permite estruturar a aplicação conforme os dispositivos e/ou plataformas utilizadas, ou ainda conforme uma versão da aplicação sem a necessidade de alterar a estrutura do código.

Encerrando o processo de compilação

Em alguns momentos é necessário instruir o compilador para abortar o processo de compilação. A diretiva #error instrui o pré-processador a gerar uma mensagem de erro e encerrar o processo de compilação.

Considere, por exemplo, que o dispositivo utilizado na aplicação não foi definido.

Nesse caso, se o dispositivo não é válido, a aplicação não é compilada.

Conclusão

Nesse artigo foram apresentados, de maneira introdutória, alguns recursos do pré-processador C que podem ser empregados para realizar a compilação condicional de código. As diretivas de compilação condicional podem ser utilizadas em qualquer parte do projeto, permitindo estruturar e organizar o código que é compilado.

Na terceira parte desta série serão apresentadas outras funções do pré-processador C e algumas técnicas de expansão de macros.

Saiba mais: Série “Pré-processador C”

– 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

Outros artigos da série

<< Pré-processador C – Parte 1Pré-processador C: Diagnóstico – Parte 3 >>
Notificações
Notificar
guest
7 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
valrei
valrei
08/07/2021 17:04

Excelente, pois estrou no inicio em programação em “c”.

Cesar Junior
Cesar Junior
12/09/2015 09:55

Parabéns pelo artigo.

Fernando Deluno Garcia
Fernando Deluno Garcia
Reply to  Cesar Junior
13/09/2015 11:17

Obrigado, Cesar!

Rafael Dias
Rafael Dias
03/09/2015 12:50

muito bom o artigo.
Este é um tópico muito legal, útil e capcioso em desenvolvimento de software em C/C++

Fernando Deluno Garcia
Fernando Deluno Garcia
Reply to  Rafael Dias
03/09/2015 18:13

Obrigado, Rafael!

Com certeza, o pré-processador é muito útil para desenvolver aplicações com certa flexibilidade, manutenibilidade e possibilidade de extensão. Mas como você mesmo disse, é capcioso, uma vez que a utilização incorreta pode causar sérias consequências para a estrutura do projeto.

Rafael Dias
Rafael Dias
Reply to  Fernando Deluno Garcia
03/09/2015 19:44

o uso incorreto pode não trazer só conseqüências para o projeto… Pode trazer conseqüências para a sanidade dos desenvolvedores envolvidos.

Fernando Deluno Garcia
Fernando Deluno Garcia
Reply to  Rafael Dias
09/09/2015 09:21

haha certamente! Entender o que foi feito já pode ser um problema, encontrar e resolver algum erro então…..

WEBINAR

Visão Computacional para a redução de erros em processos manuais

DATA: 23/09 ÀS 17:00 H