_DEBUG vs NDEBUG


142

Quale definizione del preprocessore dovrebbe essere utilizzata per specificare sezioni di codice di debug?

Utilizzare #ifdef _DEBUGo #ifndef NDEBUGc'è un modo migliore per farlo, ad esempio #define MY_DEBUG?

Penso che _DEBUGsia specifico di Visual Studio, è lo standard NDEBUG?

Risposte:


113

Visual Studio definisce _DEBUGquando si specifica l' opzione /MTdo /MDd, NDEBUGdisabilita le asserzioni C standard. Usali quando appropriato, ad esempio _DEBUGse vuoi che il tuo codice di debug sia coerente con le tecniche di debug di MS CRT e NDEBUGse vuoi essere coerente assert().

Se si definiscono le proprie macro di debug (e non si compromette il compilatore o il runtime C), evitare di iniziare i nomi con un trattino basso, poiché sono riservati.


19
+1. NDEBUG in particolare può essere # non definito e # definito in una singola TU (e la reinclusione di <assert.h> modifica di conseguenza la macro assert). Poiché questo è diverso da quello previsto / desiderato, è comune utilizzare un'altra macro per controllare un flag di debug "a livello di compilazione" come dice questa risposta.

1
Apparentemente, è il compilatore stesso che definisce queste macro e non Visual Studio (l'IDE). Grazie mille per questa risposta!
Niklas R,

NDEBUG non è definito anche quando si utilizzano modelli di applicazioni da Windows Driver Kit 8.1. In questo caso, potrebbe essere necessario fare affidamento su _DEBUG.
navossoc,

53

NDEBUG è standard?

Sì, è una macro standard con il semantico "Not Debug" per gli standard C89, C99, C ++ 98, C ++ 2003, C ++ 2011, C ++ 2014. Non ci sono _DEBUGmacro negli standard.

Lo standard C ++ 2003 invia il lettore a "pagina 326" a "17.4.2.1 Intestazioni" allo standard C.

Che NDEBUG è simile a Questo è lo stesso della libreria C standard.

In C89 (i programmatori C hanno definito questo standard come standard C) nella sezione "4.2 DIAGNOSTICA" è stato detto

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

Se NDEBUG è definito come un nome di macro nel punto nel file di origine in cui è incluso, la macro di asserzione viene definita semplicemente come

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

Se si guarda al significato delle _DEBUGmacro in Visual Studio https://msdn.microsoft.com/en-us/library/b0084kay.aspx , si vedrà che questa macro viene definita automaticamente dalla tua versione della libreria di runtime della lingua.


50

Mi affido NDEBUG, perché è l'unico il cui comportamento è standardizzato tra compilatori e implementazioni (vedere la documentazione per la macro assert standard). La logica negativa è un piccolo speedbump di leggibilità, ma è un linguaggio comune a cui puoi rapidamente adattarti.

Fare affidamento su qualcosa del genere _DEBUGsignificherebbe fare affidamento su un dettaglio di implementazione di un particolare compilatore e implementazione della libreria. Altri compilatori possono o meno scegliere la stessa convenzione.

La terza opzione è definire la tua macro per il tuo progetto, il che è abbastanza ragionevole. Avere la propria macro offre la portabilità tra le implementazioni e consente di abilitare o disabilitare il codice di debug indipendentemente dalle asserzioni. Tuttavia, in generale, sconsiglio di avere diverse classi di informazioni di debug che sono abilitate in fase di compilazione, poiché provoca un aumento del numero di configurazioni che devi costruire (e testare) per un vantaggio discutibilmente piccolo.

Con una di queste opzioni, se usi codice di terze parti come parte del tuo progetto, dovrai essere consapevole di quale convenzione utilizza.


1
#if !defined(NDEBUG)<- @HostileFork non è quello che volevi dire? #ifno #ifdef?
Bob Stein,

1
Commento originale corretto tramite @BobStein: "Qualcosa ho preso a fare a (leggermente) mitigare la leggibilità 'speedbump' è che quando si parla di una condizione di uso non-debug #ifdef NDEBUG... ma quindi chiamare una particolare attenzione alla logica negativa con #if !defined(NDEBUG). Altrimenti è un po 'difficile trovare la n #ifndef NDEBUG"
HostileFork dice che non fidarti di SE

17

La macro NDEBUG controlla se le assert()istruzioni sono attive o meno.

A mio avviso, questo è separato da qualsiasi altro debug, quindi uso qualcosa di diverso da NDEBUG controllo delle informazioni di debug nel programma. Quello che uso varia a seconda del framework con cui sto lavorando; sistemi diversi hanno macro abilitanti diverse e utilizzo tutto ciò che è appropriato.

Se non esiste un framework, utilizzerei un nome senza un trattino basso iniziale; quelli tendono ad essere riservati all '"implementazione" e cerco di evitare problemi con le collisioni di nomi - doppiamente quando il nome è una macro.


Puoi spiegare perché consideri le affermazioni distinte da altri tipi di debug? In quali scenari vorresti uno e non l'altro?
Adrian McCarthy,

4
Tengo le asserzioni attive anche quando non compilo altre strutture di debug o di tracciamento nel codice. Le asserzioni identificano situazioni impossibili. La traccia generale e il debug sono completamente separati dall'IMO.
Jonathan Leffler,

2
@AdrianMcCarthy: se hai attivato TUTTO il debug, i programmi possono essere eseguiti INCREDIBILMENTE lentamente. Quindi è comune classificare i tipi di debug e consentire alle persone di abilitarli / disabilitarli separatamente. MSVC ne ha due o tre che usano per abilitare / disabilitare vari debug per la libreria standard, come std :: vector.
Mooing Duck

@MooingDuck: concordato, ma distingue tra "debug disponibile e abilitato" e "debug disponibile ma disabilitato" e "debug non disponibile". La decisione disponibile / non disponibile è un problema di tempo di compilazione (in codice C o C ++) e l'abilitato / disabilitato è quindi una decisione di runtime quando il debug è disponibile. Solo i sistemi di debug più crudi funzionano con la modalità "disponibile significa abilitato". (Detto questo, il greggio può essere efficace e ci sono un sacco di rozzi - ma abbastanza efficaci - sistemi di debug in natura!)
Jonathan Leffler

2
@MooingDuck: Sì, alcuni codici di debug possono variare lentamente. In tal caso, potresti voler un modo per controllare se il codice lento viene eseguito indipendentemente dai controlli banali. Ma non è lo stesso che inserire asserzioni in una categoria e #ifcodice controllato nell'altra. assert(huge_object.IsValid());potrebbe essere lento mentre assert(ptr != nullptr);probabilmente non lo è. Concordo con Jonathan sul fatto che la registrazione e la traccia dovrebbero probabilmente essere distinte dalle asserzioni, almeno in progetti più grandi, ma non penso alla registrazione o alla traccia come codice di debug, motivo per cui ho chiesto chiarimenti.
Adrian McCarthy,

6

Sii coerente e non importa quale. Inoltre, se per qualche motivo devi interagire con un altro programma o strumento usando un determinato identificatore DEBUG, è facile da fare

#ifdef THEIRDEBUG
#define MYDEBUG
#endif //and vice-versa

4

Purtroppo DEBUGè sovraccarico pesantemente. Ad esempio, si consiglia di generare e salvare sempre un file pdb per build RELEASE. Il che significa una delle -Zxbandiere e l' -DEBUGopzione linker. Mentre si _DEBUGriferisce a versioni speciali di debug della libreria di runtime come le chiamate a malloce free. Quindi NDEBUGdisabiliterà le asserzioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.