ti-enxame.com

Existe uma maneira de verificar se uma macro está definida e é igual a um determinado valor ao mesmo tempo

Eu uso regularmente macros de pré-processamento de objeto como sinalizadores booleanos emCcode para ativar e desativar seções de código.

Por exemplo

#define DEBUG_PRINT 1

E então usá-lo como

#if(DEBUG_PRINT == 1)
    printf("%s", "Testing");
#endif

No entanto, é um problema se o arquivo de cabeçalho que contém o #define for esquecido de ser incluído no código-fonte. Como a macro não é declarada, o pré-processador a trata como se fosse igual a 0 e a instrução #if nunca é executada.

Quando o arquivo de cabeçalho é esquecido para ser incluído, não esperado, comportamento indisciplinado pode ocorrer.  

Idealmente, gostaria de poder verificar se uma macro está definida e verificar se é igual a um determinado valor, em uma linha. Se não estiver definido, o pré-processador emitirá um erro (ou aviso).

Eu estou procurando algo ao longo das linhas de:

#if-def-and-true-else-throw-error(DEBUG_PRINT)
    ...
#endif

É como uma combinação de #ifdef e #if e, se não existir, usa #error.

Eu explorei alguns caminhos, no entanto, diretivas de pré-processador não podem ser usadas dentro de um bloco #define e, até onde eu sei, não há opção de pré-processador para lançar erros/avisos se uma macro não for definida quando usada dentro de um #if declaração.

13
gbmhunter

Isso pode não funcionar para o caso geral (acho que não há uma solução geral para o que você está pedindo), mas, para o seu exemplo específico, você pode considerar alterar essa seqüência de código:

#if(DEBUG_PRINT == 1)
    printf("%s", "Testing");
#endif

para:

if (DEBUG_PRINT == 1) {
    printf("%s", "Testing");
}

Não é mais detalhado e não será compilado se DEBUG_PRINT não estiver definido ou se for definido como algo que não pode ser comparado a 1.

7
Michael Burr

tanto quanto eu posso dizer, não há opção de pré-processador para lançar erros/avisos se uma macro não é definida quando usada dentro de uma instrução #if.

Não pode ser um erro porque o padrão C especifica que o comportamento é legal. Da seção 6.10.1/3 da norma ISO C99:

Depois que todas as substituições devido à expansão de macro e o operador defined unary Tiverem sido executados, todos os identificadores restantes serão substituídos pelo número de pp 0....

Como Jim Balter observa no comentário abaixo, alguns compiladores (como o gcc) podem emitir avisos sobre isso. No entanto, como o comportamento de substituir 0 por tokens de pré-processador não reconhecidos é legal (e em muitos casos desejável), eu esperaria que a ativação desses avisos na prática gerasse uma quantidade significativa de ruído.

Não há como fazer exatamente o que você quer. Se você quiser gerar uma falha de compilação se a macro não estiver definida, você terá que fazê-lo explicitamente

#if !defined DEBUG_PRINT
#error DEBUG_PRINT is not defined.
#endif

para cada arquivo de origem que se importa. Como alternativa, você pode converter sua macro em uma macro de função e evitar o uso de #if. Por exemplo, você pode definir uma macro DEBUG_PRINT que se expande para uma chamada printf para compilações de depuração, mas se expande para nada em compilações que não sejam de depuração. Qualquer arquivo que negligencie incluir o cabeçalho que define a macro falhará na compilação.

9
jamesdlin

Em vez de usar DEBUG_PRINT diretamente em seus arquivos de origem, coloque isso no arquivo de cabeçalho:

#if !defined(DEBUG_PRINT)
    #error DEBUG_PRINT is not defined
#endif

#if DEBUG_PRINT
    #define PrintDebug([args]) [definition]
#else
    #define PrintDebug
#endif

Qualquer arquivo de origem que use o PrintDebug, mas não inclui o arquivo de cabeçalho, falhará na compilação.

Se você precisar de código diferente das chamadas para o PrintDebug a ser compilado com base no DEBUG_PRINT, considere o uso da sugestão de Michael Burr de usar plain if em vez de #if (sim, o otimizador não gerará código dentro de um teste falso constante).

Edit: E você pode generalizar PrintDebug acima para incluir ou excluir código arbitrário, desde que você não tenha vírgulas que se pareçam com argumentos de macro:

#if !defined(IF_DEBUG)
    #error IF_DEBUG is not defined
#endif

#if IF_DEBUG
    #define IfDebug(code) code
#else
    #define IfDebug(code)
#endif

Então você pode escrever coisas como

IfDebug(int count1;)  // IfDebug(int count1, count2;) won't work
IfDebug(int count2;)
...
IfDebug(count1++; count2++;)
8
Jim Balter

Sim você pode verificar ambos:

#if defined DEBUG  &&  DEBUG == 1
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif

Neste exemplo, mesmo quando #define DEBUG 0, mas não é igual a 1, nada será impresso.

Você pode fazer isso mesmo:

#if defined DEBUG  &&  DEBUG
#  define D(...) printf(__VA_ARGS__)
#else
#  define D(...)
#endif

Aqui se você #define DEBUG 0 e depois D(1,2,3) também nada será impresso

DOC

2
Eugen Konkov

Basta criar uma macro DEBUG_PRINT que faça a impressão real:

#define DEBUG_PRINT(n, str)    \
                               \
  if(n == 1)                   \
  {                            \
    printf("%s", str);         \
  }                            \
  else if(n == 2)              \
  {                            \
    do_something_else();       \
  }                            \
                               \
#endif


#include <stdio.h>

int main()
{
  DEBUG_PRINT(1, "testing");
}

Se a macro não estiver definida, você receberá um erro do compilador porque o símbolo não é reconhecido.

0
Lundin
#if 0 // 0/1
#define DEBUG_PRINT printf("%s", "Testing")
#else
#define DEBUG_PRINT printf("%s")
#endif

Então, quando "se 0" não fará nada e quando "se 1" executar a macro definida.

0
Sam Keith