Odpowiedzi:
Program Visual Studio definiuje, _DEBUG
gdy określisz opcję /MTd
lub /MDd
, NDEBUG
wyłącza asercje w standardzie C. Używaj ich w odpowiednich przypadkach, np. _DEBUG
Jeśli chcesz, aby Twój kod debugowania był spójny z technikami debugowania MS CRT i NDEBUG
jeś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.
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 _DEBUG
standardach 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 _DEBUG
makr 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.
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 _DEBUG
był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.
#if !defined(NDEBUG)
<- @HostileFork czy nie to miałeś na myśli? #if
nie #ifdef
?
#ifdef NDEBUG
... ale zwróć szczególną uwagę na logikę negatywną #if !defined(NDEBUG)
. W przeciwnym razie trochę trudno jest złapać n #ifndef NDEBUG
”
Makro NDEBUG
kontroluje, czy assert()
instrukcje są aktywne, czy nie.
Moim zdaniem jest to niezależne od jakiegokolwiek innego debugowania - więc używam czegoś innego niż NDEBUG
kontrolowanie 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.
#if
kontrolowanego 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.
Niestety DEBUG
jest mocno przeciążony. Na przykład, zaleca się, aby zawsze generować i zapisywać plik pdb dla wersji RELEASE. Co oznacza jedną z -Zx
flag i -DEBUG
opcję konsolidatora. Podczas gdy _DEBUG
odnosi się do specjalnych wersji debugowania biblioteki wykonawczej, takich jak wywołania malloc
i free
. Następnie NDEBUG
wyłączy asercje.