_DEBUG vs NDEBUG

142

Welche Präprozessordefinition sollte verwendet werden, um Debug-Codeabschnitte anzugeben?

Verwenden Sie #ifdef _DEBUGoder #ifndef NDEBUGoder gibt es einen besseren Weg, um es zu tun, z #define MY_DEBUG.

Ich denke, _DEBUGist Visual Studio spezifisch, ist NDEBUG Standard?

deft_code
quelle

Antworten:

113

Visual Studio definiert, _DEBUGwann Sie die Option /MTdoder angeben /MDd, und NDEBUGdeaktiviert Standard-C-Zusicherungen. Verwenden Sie sie gegebenenfalls, dh _DEBUGwenn Sie möchten, dass Ihr Debugging-Code mit den MS CRT-Debugging-Techniken übereinstimmt , und NDEBUGwenn Sie mit diesen übereinstimmen möchten assert().

Wenn Sie Ihre eigenen Debugging-Makros definieren (und den Compiler oder die C-Laufzeit nicht hacken), vermeiden Sie es, Namen mit einem Unterstrich zu beginnen, da diese reserviert sind.

Christoph
quelle
19
+1. Insbesondere NDEBUG darf innerhalb einer einzelnen TU # undef'd und # define'd sein (und durch erneutes Einschließen von <assert.h> wird das assert-Makro entsprechend geändert). Da dies anders als erwartet / erwünscht ist, wird häufig ein anderes Makro verwendet, um ein "kompilierungsweites" Debug-Flag zu steuern, wie in dieser Antwort angegeben.
1
Anscheinend ist es der Compiler selbst, der diese Makros definiert, und nicht Visual Studio (die IDE). Vielen Dank für diese Antwort!
Niklas R
NDEBUG ist nicht definiert, wenn Anwendungsvorlagen aus Windows Driver Kit 8.1 verwendet werden. In diesem Fall müssen Sie sich möglicherweise auf _DEBUG verlassen.
Navossoc
53

Ist NDEBUG Standard?

Ja, es ist ein Standardmakro mit der semantischen Bezeichnung "Nicht debuggen" für die Standards C89, C99, C ++ 98, C ++ 2003, C ++ 2011, C ++ 2014. _DEBUGDie Standards enthalten keine Makros.

C ++ 2003 Standard Senden Sie den Reader auf "Seite 326" unter "17.4.2.1 Header" an Standard C.

Dieser NDEBUG ist ähnlich wie Dies ist derselbe wie die Standard C-Bibliothek.

In C89 (C-Programmierer nannten diesen Standard als Standard C) wurde im Abschnitt "4.2 DIAGNOSE" gesagt

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

Wenn NDEBUG an der Stelle in der Quelldatei, an der es enthalten ist, als Makroname definiert ist, wird das Assert-Makro einfach als definiert

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

Wenn Sie sich die Bedeutung von _DEBUGMakros in Visual Studio https://msdn.microsoft.com/en-us/library/b0084kay.aspx ansehen , wird ersichtlich, dass dieses Makro automatisch durch Ihre Wahl der Version der Sprachlaufzeitbibliothek definiert wird.

Bruziuz
quelle
50

Ich verlasse mich darauf NDEBUG, weil es das einzige ist, dessen Verhalten über Compiler und Implementierungen hinweg standardisiert ist (siehe Dokumentation für das Standard-Assert-Makro). Die negative Logik ist ein kleiner Speedbump für die Lesbarkeit, aber es ist eine gängige Redewendung, an die Sie sich schnell anpassen können.

Sich auf so etwas zu verlassen, _DEBUGwürde bedeuten, sich auf ein Implementierungsdetail eines bestimmten Compilers und einer bestimmten Bibliotheksimplementierung zu verlassen. Andere Compiler können dieselbe Konvention wählen oder nicht.

Die dritte Möglichkeit besteht darin, ein eigenes Makro für Ihr Projekt zu definieren, was durchaus sinnvoll ist. Mit Ihrem eigenen Makro können Sie Implementierungen über Implementierungen hinweg durchführen und Ihren Debugging-Code unabhängig von den Zusicherungen aktivieren oder deaktivieren. Im Allgemeinen rate ich jedoch davon ab, verschiedene Klassen von Debugging-Informationen zu haben, die zur Kompilierungszeit aktiviert werden, da dies zu einer Zunahme der Anzahl von Konfigurationen führt, die Sie erstellen (und testen) müssen, um einen wohl geringen Nutzen zu erzielen.

Wenn Sie bei einer dieser Optionen Code von Drittanbietern als Teil Ihres Projekts verwenden, müssen Sie wissen, welche Konvention verwendet wird.

Adrian McCarthy
quelle
1
#if !defined(NDEBUG)<- @HostileFork hast du das nicht gemeint? #ifnicht #ifdef?
Bob Stein
1
Der ursprüngliche Kommentar wurde über @BobStein korrigiert: "Etwas, das ich unternommen habe, um die Lesbarkeit" Speedbump "(geringfügig) zu verringern, ist, dass, wenn über eine No-Debug-Bedingung gesprochen wird, #ifdef NDEBUG... aber dann besondere Aufmerksamkeit auf die negative Logik mit gelenkt wird #if !defined(NDEBUG). Ansonsten ist es ein wenig schwierig, das n in #ifndef NDEBUG"
HostileFork sagt, traue SE
17

Das Makro NDEBUGsteuert, ob assert()Anweisungen aktiv sind oder nicht.

Meiner Ansicht nach unterscheidet sich das von jedem anderen Debugging. Daher verwende ich etwas anderes als NDEBUGdie Steuerung der Debugging-Informationen im Programm. Was ich benutze, hängt vom Framework ab, mit dem ich arbeite. Verschiedene Systeme haben unterschiedliche Aktivierungsmakros, und ich verwende alles, was angemessen ist.

Wenn es kein Framework gibt, würde ich einen Namen ohne führenden Unterstrich verwenden. Diese sind in der Regel der Implementierung vorbehalten, und ich versuche, Probleme mit Namenskollisionen zu vermeiden - doppelt so, wenn der Name ein Makro ist.

Jonathan Leffler
quelle
Können Sie erklären, warum Sie Asserts als von anderen Debugging-Arten verschieden betrachten? In welchen Szenarien möchten Sie das eine und nicht das andere?
Adrian McCarthy
4
Ich halte Asserts aktiv, auch wenn ich keine anderen Debugging- oder Tracing-Funktionen in den Code kompiliere. Behauptungen identifizieren unmögliche Situationen. Das allgemeine Tracing und Debugging ist IMO völlig unabhängig davon.
Jonathan Leffler
2
@AdrianMcCarthy: Wenn Sie ALLE Debugging aktiviert haben, kann dies dazu führen, dass Programme UNGLAUBLICH langsam ausgeführt werden. Daher ist es üblich, Debugging-Typen zu kategorisieren und sie den Benutzern zu ermöglichen, sie separat zu aktivieren / deaktivieren. MSVC verfügt über zwei oder drei, mit denen verschiedene Debugging-Vorgänge für die Standardbibliothek wie std :: vector aktiviert / deaktiviert werden.
Mooing Duck
@MooingDuck: Einverstanden, aber unterscheiden Sie zwischen "Debugging verfügbar und aktiviert" und "Debugging verfügbar, aber deaktiviert" und "Debugging nicht verfügbar". Die verfügbare / nicht verfügbare Entscheidung ist ein Problem mit der Kompilierungszeit (in C- oder C ++ - Code), und die aktivierte / deaktivierte Entscheidung ist dann eine Laufzeitentscheidung, wenn das Debuggen verfügbar ist. Nur die gröbsten Debugging-Systeme arbeiten mit dem Modus "Verfügbare Mittel aktiviert". (Das heißt, Rohöl kann effektiv sein, und es gibt eine Menge Rohöl - aber effektiv genug - Debugging-Systeme in freier Wildbahn!)
Jonathan Leffler
2
@MooingDuck: Ja, einige Debugging-Codes können langsam variieren. In diesem Fall möchten Sie möglicherweise steuern können, ob der langsame Code unabhängig von den trivialen Überprüfungen ausgeführt wird. Dies ist jedoch nicht dasselbe wie das #ifEinfügen von Behauptungen in eine Kategorie und von kontrolliertem Code in die andere. assert(huge_object.IsValid());könnte langsam sein, während es assert(ptr != nullptr);wahrscheinlich nicht ist. Ich stimme Jonathan zu, dass sich Protokollierung und Ablaufverfolgung wahrscheinlich von Behauptungen unterscheiden sollten, zumindest in größeren Projekten, aber ich denke nicht an Protokollierung oder Ablaufverfolgung als Debug-Code, weshalb ich um Klarstellung gebeten habe.
Adrian McCarthy
6

Seien Sie konsequent und es spielt keine Rolle, welche. Auch wenn Sie aus irgendeinem Grund mit einem anderen Programm oder Tool unter Verwendung einer bestimmten DEBUG-Kennung zusammenarbeiten müssen, ist dies einfach

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

Ist leider DEBUGstark überlastet. Beispielsweise wird empfohlen, immer eine PDF-Datei für RELEASE-Builds zu generieren und zu speichern. Was bedeutet, eines der -ZxFlags und -DEBUGLinker-Option. While _DEBUGbezieht sich auf spezielle Debug-Versionen der Laufzeitbibliothek, z. B. Aufrufe von mallocund free. Dann NDEBUGwerden Zusicherungen deaktiviert.

James
quelle