_DEBUG vs NDEBUG

142

Qual definição de pré-processador deve ser usada para especificar seções de depuração do código?

Use #ifdef _DEBUGou #ifndef NDEBUGou existe uma maneira melhor de fazê-lo, por exemplo #define MY_DEBUG?

Eu acho que _DEBUGé específico do Visual Studio, é o padrão NDEBUG?

deft_code
fonte

Respostas:

113

O Visual Studio define _DEBUGquando você especifica a opção /MTdou /MDd, NDEBUGdesativa as asserções C padrão. Use-os quando apropriado, ou seja, _DEBUGse você deseja que seu código de depuração seja consistente com as técnicas de depuração do MS CRT e NDEBUGse você deseja ser consistente comassert() .

Se você definir suas próprias macros de depuração (e não hackear o compilador ou o tempo de execução C), evite iniciar nomes com um sublinhado, pois eles são reservados.

Christoph
fonte
19
+1. NDEBUG em particular, pode ser # indefinido e # definido dentro de uma única TU (e reincluir <assert.h> altera a macro assert de acordo). Como isso é diferente do esperado / desejado, é comum usar outra macro para controlar um sinalizador de depuração "em toda a compilação", como diz esta resposta.
1
Aparentemente, é o próprio compilador que define essas macros e não o Visual Studio (o IDE). Muito obrigado por esta resposta!
Niklas R
NDEBUG não está definido ao usar modelos de aplicativos do Windows Driver Kit 8.1 também. Nesse caso, você pode precisar confiar em _DEBUG.
Navossoc 07/04
53

O NDEBUG é padrão?

Sim, é uma macro padrão com a semântica "Sem depuração" para os padrões C89, C99, C ++ 98, C ++ 2003, C ++ 2011, C ++ 2014. Não há _DEBUGmacros nos padrões.

O padrão C ++ 2003 envia o leitor na "página 326" em "17.4.2.1 Cabeçalhos" para o padrão C.

Esse NDEBUG é semelhante, pois é igual à biblioteca C padrão.

Em C89 (programadores C chamaram esse padrão como padrão C) na seção "4.2 DIAGNÓSTICOS", foi dito

http://port70.net/~nsz/c/c89/c89-draft.html

Se NDEBUG for definido como um nome de macro no ponto no arquivo de origem em que está incluído, a macro assert será definida simplesmente como

     #define assert(ignore) ((void)0)

Se observar o significado das _DEBUGmacros no Visual Studio https://msdn.microsoft.com/en-us/library/b0084kay.aspx , será visto que essa macro é definida automaticamente pela sua escolha da versão da biblioteca de tempo de execução do idioma.

bruziuz
fonte
50

Eu confio NDEBUG, porque é o único cujo comportamento é padronizado entre compiladores e implementações (consulte a documentação para a macro assert padrão). A lógica negativa é uma pequena aceleração de legibilidade, mas é um idioma comum ao qual você pode se adaptar rapidamente.

Confiar em algo como _DEBUGseria confiar em um detalhe de implementação de um determinado compilador e implementação de biblioteca. Outros compiladores podem ou não escolher a mesma convenção.

A terceira opção é definir sua própria macro para o seu projeto, o que é bastante razoável. Ter sua própria macro fornece portabilidade entre implementações e permite ativar ou desativar o código de depuração independentemente das asserções. Embora, em geral, desaconselho a existência de diferentes classes de informações de depuração habilitadas no momento da compilação, pois isso causa um aumento no número de configurações que você precisa criar (e testar) para obter benefícios indiscutivelmente pequenos.

Com qualquer uma dessas opções, se você usar código de terceiros como parte do seu projeto, precisará conhecer qual convenção ele usa.

Adrian McCarthy
fonte
1
#if !defined(NDEBUG)<- @HostileFork não é isso que você quis dizer? #ifnão #ifdef?
Bob Stein
1
Comentário original corrigido via @BobStein: "Algo que eu levei a fazer para (levemente) mitigar a legibilidade" speedbump "é que, quando se fala em uma condição sem depuração, use #ifdef NDEBUG... mas, em seguida, chame atenção especial para a lógica negativa #if !defined(NDEBUG). Caso contrário, é um pouco difícil de entender #ifndef NDEBUG"
HostileFork diz que não confie em
17

A macro NDEBUGcontrola se as assert()instruções estão ativas ou não.

Na minha opinião, isso é separado de qualquer outra depuração - então eu uso algo diferente de NDEBUGcontrolar as informações de depuração no programa. O que eu uso varia, dependendo da estrutura com a qual estou trabalhando; sistemas diferentes têm macros ativadoras diferentes, e eu uso o que for apropriado.

Se não houver estrutura, eu usaria um nome sem um sublinhado à esquerda; esses tendem a ser reservados à 'implementação' e tento evitar problemas com colisões de nomes - duplamente quando o nome é uma macro.

Jonathan Leffler
fonte
Você pode explicar por que você considera assertivas distintas de outros tipos de depuração? Em quais cenários você deseja um e não o outro?
Adrian McCarthy
4
Mantenho as declarações ativas, mesmo quando não compilo outros recursos de depuração ou rastreamento no código. As asserções identificam situações impossíveis. O rastreamento geral e a depuração são IMO totalmente separados disso.
Jonathan Leffler
2
@AdrianMcCarthy: se você tiver TODAS as depurações ativadas, poderá fazer com que os programas sejam executados INCRÍVEL lentamente. Portanto, é comum categorizar os tipos de depuração e permitir que as pessoas os habilitem / desabilitem separadamente. O MSVC possui dois ou três que eles usam para habilitar / desabilitar várias depurações para a biblioteca padrão, como std :: vector.
Mooing Duck
@MooingDuck: concordou, mas distingue entre 'depuração disponível e habilitada' e 'depuração disponível mas desativada' e 'depuração não disponível'. A decisão disponível / não disponível é um problema de tempo de compilação (no código C ou C ++), e o ativado / desativado é uma decisão de tempo de execução quando a depuração está disponível. Somente os sistemas de depuração mais brutos funcionam com o modo 'meios disponíveis habilitados'. (Dito isto, bruto pode ser eficaz, e há uma enorme quantidade de crude - mas bastante eficazes - sistemas de depuração lá fora na selva)
Jonathan Leffler
2
@MooingDuck: Sim, alguns códigos de depuração podem variar lentamente. Nesse caso, você pode querer uma maneira de controlar se o código lento é executado independentemente das verificações triviais. Mas isso não é o mesmo que colocar asserções em uma categoria e #ifcódigo controlado na outra. assert(huge_object.IsValid());pode ser lento enquanto assert(ptr != nullptr);provavelmente não é. Concordo com Jonathan que o log e o rastreamento devem provavelmente ser diferentes das asserções, pelo menos em projetos maiores, mas não penso em log ou rastreamento como código de depuração, e foi por isso que pedi esclarecimentos.
Adrian McCarthy
6

Seja consistente e não importa qual deles. Além disso, se por algum motivo você precisar interoperar com outro programa ou ferramenta usando um determinado identificador DEBUG, é fácil fazer isso.

#ifdef THEIRDEBUG
#define MYDEBUG
#endif //and vice-versa
Earlz
fonte
4

Infelizmente DEBUGestá sobrecarregado. Por exemplo, é recomendável sempre gerar e salvar um arquivo pdb para compilações RELEASE. O que significa uma das opções de -Zxsinalizador e -DEBUGvinculador. Embora _DEBUGesteja relacionado a versões especiais de depuração da biblioteca de tempo de execução, como chamadas para malloce free. Em seguida NDEBUG, desabilitará as asserções.

James
fonte