_DEBUG vs NDEBUG

142

Której definicji preprocesora należy użyć do określenia sekcji kodu do debugowania?

Użyj #ifdef _DEBUGlub #ifndef NDEBUGczy jest lepszy sposób, aby to zrobić, np. #define MY_DEBUG?

Myślę, że _DEBUGjest to specyficzne dla Visual Studio, czy standard NDEBUG?

deft_code
źródło

Odpowiedzi:

113

Program Visual Studio definiuje, _DEBUGgdy określisz opcję /MTdlub /MDd, NDEBUGwyłącza asercje w standardzie C. Używaj ich w odpowiednich przypadkach, np. _DEBUGJeśli chcesz, aby Twój kod debugowania był spójny z technikami debugowania MS CRT i NDEBUGjeśli chcesz być spójny z assert().

Jeśli zdefiniujesz własne makra debugowania (i nie włamujesz się do kompilatora ani środowiska wykonawczego C), unikaj rozpoczynania nazw od podkreślenia, ponieważ są one zarezerwowane.

Christoph
źródło
19
+1. W szczególności NDEBUG może być # undef'd i # define'd w jednej jednostce tłumaczeniowej (a ponowne uwzględnienie <assert.h> odpowiednio zmienia makro assert). Ponieważ jest to inne niż oczekiwano / pożądane, często używa się innego makra do sterowania flagą debugowania „obejmującą całą kompilację”, jak mówi ta odpowiedź.
1
Najwyraźniej to sam kompilator definiuje te makra, a nie Visual Studio (IDE). Wielkie dzięki za tę odpowiedź!
Niklas R
NDEBUG nie jest zdefiniowany w przypadku używania szablonów aplikacji z zestawu Windows Driver Kit 8.1. W takim przypadku może być konieczne skorzystanie z narzędzia _DEBUG.
navossoc
53

Czy NDEBUG jest standardem?

Tak, jest to standardowe makro z semantycznym „Not Debug” dla standardów C89, C99, C ++ 98, C ++ 2003, C ++ 2011, C ++ 2014. W _DEBUGstandardach nie ma makr.

Standard C ++ 2003 wysyła czytelnika na „stronę 326” w „17.4.2.1 Nagłówki” do standardu C.

Ten NDEBUG jest podobny do tego, co jest tym samym, co standardowa biblioteka C.

W C89 (programiści C nazywali ten standard standardem C) w sekcji "4.2 DIAGNOSTYKA" powiedziano

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

Jeśli NDEBUG jest zdefiniowany jako nazwa makra w punkcie w pliku źródłowym, w którym jest uwzględniony, makro assert jest definiowane po prostu jako

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

Jeśli spojrzysz na znaczenie _DEBUGmakr w Visual Studio https://msdn.microsoft.com/en-us/library/b0084kay.aspx , zobaczysz, że to makro jest automatycznie definiowane przez wybór wersji biblioteki środowiska uruchomieniowego języka.

bruziuz
źródło
50

Polegam na tym NDEBUG, ponieważ jest to jedyny, którego zachowanie jest znormalizowane między kompilatorami i implementacjami (zobacz dokumentację standardowego makra assert). Logika negatywna to niewielki wzrost czytelności, ale jest to powszechny idiom, do którego można szybko się dostosować.

Poleganie na czymś podobnym _DEBUGbyłoby poleganiem na szczegółach implementacji konkretnego kompilatora i implementacji biblioteki. Inni kompilatorzy mogą, ale nie muszą, wybrać tę samą konwencję.

Trzecią opcją jest zdefiniowanie własnego makra dla projektu, co jest całkiem rozsądne. Posiadanie własnego makra zapewnia przenośność między implementacjami i umożliwia włączanie lub wyłączanie kodu debugowania niezależnie od stwierdzeń. Chociaż, ogólnie rzecz biorąc, odradzam posiadanie różnych klas informacji debugowania, które są włączane w czasie kompilacji, ponieważ powoduje to wzrost liczby konfiguracji, które musisz zbudować (i przetestować) z prawdopodobnie niewielkimi korzyściami.

W przypadku dowolnej z tych opcji, jeśli używasz kodu innej firmy w ramach swojego projektu, musisz wiedzieć, jakiej konwencji używa.

Adrian McCarthy
źródło
1
#if !defined(NDEBUG)<- @HostileFork czy nie to miałeś na myśli? #ifnie #ifdef?
Bob Stein
1
Oryginalny komentarz poprawiony przez @BobStein: „Coś, co podjąłem, aby (nieznacznie) złagodzić czytelność„ speedbump ”, polega na tym, że kiedy mówimy o warunku braku debugowania, użyj #ifdef NDEBUG... ale zwróć szczególną uwagę na logikę negatywną #if !defined(NDEBUG). W przeciwnym razie trochę trudno jest złapać n #ifndef NDEBUG
mówi HostileFork nie ufaj SE
17

Makro NDEBUGkontroluje, czy assert()instrukcje są aktywne, czy nie.

Moim zdaniem jest to niezależne od jakiegokolwiek innego debugowania - więc używam czegoś innego niż NDEBUGkontrolowanie informacji debugowania w programie. To, czego używam, różni się w zależności od frameworka, z którym pracuję; różne systemy mają różne makra włączające i używam tego, co jest odpowiednie.

Jeśli nie ma frameworka, użyłbym nazwy bez początkowego podkreślenia; są one zwykle zarezerwowane dla „implementacji” i staram się unikać problemów z kolizjami nazw - podwójnie, gdy nazwa jest makrem.

Jonathan Leffler
źródło
Czy możesz wyjaśnić, dlaczego uważasz, że potwierdzenia różnią się od innych typów debugowania? W jakich scenariuszach chciałbyś mieć jeden, a nie drugi?
Adrian McCarthy
4
Utrzymuję aktywne potwierdzenia nawet wtedy, gdy nie kompiluję innych funkcji debugowania lub śledzenia do kodu. Asercje identyfikują niemożliwe sytuacje. Ogólne śledzenie i debugowanie jest całkowicie niezależne od IMO.
Jonathan Leffler
2
@AdrianMcCarthy: jeśli masz włączone WSZYSTKIE debugowanie, może to spowodować, że programy będą działać NIESAMOWICIE wolno. Dlatego często kategoryzuje się typy debugowania i pozwala ludziom osobno je włączać / wyłączać. MSVC ma dwa lub trzy, których używają do włączania / wyłączania różnych metod debugowania dla biblioteki standardowej, takich jak std :: vector.
Mooing Duck
@MooingDuck: Zgoda, ale rozróżnia „debugowanie dostępne i włączone” oraz „debugowanie dostępne, ale wyłączone” oraz „debugowanie niedostępne”. Decyzja o dostępności / niedostępności jest kwestią czasu kompilacji (w kodzie C lub C ++), a opcja włączona / wyłączona jest wówczas decyzją w czasie wykonywania, gdy debugowanie jest dostępne. Tylko najbardziej prymitywne systemy debugowania działają w trybie „dostępne środki włączone”. (To powiedziawszy, surowy może być skuteczny, a jest bardzo dużo prymitywnych - ale wystarczająco skutecznych - systemów debugowania na wolności!)
Jonathan Leffler
2
@MooingDuck: Tak, niektóre kody do debugowania mogą działać wolno. W tym przypadku, może chcesz sposobem na kontrolowanie, czy powolny kod działa niezależnie od błahych kontroli. Ale to nie to samo, co umieszczanie asercji w jednej kategorii, a #ifkontrolowanego kodu w drugiej. assert(huge_object.IsValid());może być powolny, podczas gdy assert(ptr != nullptr);prawdopodobnie nie. Zgadzam się z Jonathanem, że logowanie i śledzenie powinny prawdopodobnie różnić się od asercji, przynajmniej w większych projektach, ale nie myślę o logowaniu lub śledzeniu jako o kodzie debugowania, dlatego poprosiłem o wyjaśnienie.
Adrian McCarthy
6

Bądź konsekwentny i nie ma znaczenia który. Również jeśli z jakiegoś powodu musisz współpracować z innym programem lub narzędziem przy użyciu określonego identyfikatora DEBUG, jest to łatwe

#ifdef THEIRDEBUG
#define MYDEBUG
#endif //and vice-versa
Earlz
źródło
4

Niestety DEBUGjest mocno przeciążony. Na przykład, zaleca się, aby zawsze generować i zapisywać plik pdb dla wersji RELEASE. Co oznacza jedną z -Zxflag i -DEBUGopcję konsolidatora. Podczas gdy _DEBUGodnosi się do specjalnych wersji debugowania biblioteki wykonawczej, takich jak wywołania malloci free. Następnie NDEBUGwyłączy asercje.

James
źródło