To może być kwestia stylu, ale w naszym zespole deweloperów jest trochę podziałów i zastanawiałem się, czy ktoś inny ma jakieś pomysły w tej sprawie ...
Zasadniczo mamy kilka instrukcji debugowania print, które wyłączamy podczas normalnego programowania. Osobiście wolę wykonać następujące czynności:
//---- SomeSourceFile.cpp ----
#define DEBUG_ENABLED (0)
...
SomeFunction()
{
int someVariable = 5;
#if(DEBUG_ENABLED)
printf("Debugging: someVariable == %d", someVariable);
#endif
}
Niektórzy członkowie zespołu wolą jednak:
// #define DEBUG_ENABLED
...
SomeFunction()
{
int someVariable = 5;
#ifdef DEBUG_ENABLED
printf("Debugging: someVariable == %d", someVariable);
#endif
}
... która z tych metod brzmi dla Ciebie lepiej i dlaczego? Mam wrażenie, że pierwsza jest bezpieczniejsza, ponieważ zawsze jest coś zdefiniowanego i nie ma niebezpieczeństwa, że mogłoby to zniszczyć inne definicje gdzie indziej.
c++
c
if-statement
coding-style
c-preprocessor
Jon Cage
źródło
źródło
#if
, możesz również używać#elif
w spójny sposób, w przeciwieństwie do with#ifdef
. Dlatego zamiast po prostu używać#define BLAH
, używaj#define BLAH 1
z#if BLAH
, itp ...Odpowiedzi:
Moja początkowa reakcja była
#ifdef
oczywiście , ale myślę, że#if
faktycznie ma to kilka znaczących zalet - oto dlaczego:Po pierwsze, można użyć
DEBUG_ENABLED
w testach preprocesora i skompilowanych. Przykład - Często potrzebuję dłuższych limitów czasu, gdy debugowanie jest włączone, więc używając#if
, mogę to napisać... zamiast ...
Po drugie, jesteś w lepszej sytuacji, jeśli chcesz dokonać migracji ze
#define
stałej globalnej.#define
Większość programistów C ++ patrzy z dezaprobatą.Po trzecie, mówisz, że masz podział w swoim zespole. Domyślam się, że oznacza to, że różni członkowie przyjęli już różne podejścia i trzeba wprowadzić standaryzację. Reguła, która
#if
jest preferowanym wyborem oznacza, że kod używający#ifdef
będzie kompilował się - i działał - nawet wtedy, gdyDEBUG_ENABLED
jest fałszywy. I to znacznie łatwiej wytropić i usunąć wyjście debugowania, który powstaje, gdy nie powinno być, niż odwrotnie.Aha, i drobny punkt dotyczący czytelności. Powinieneś móc użyć prawda / fałsz zamiast 0/1 w swoim
#define
, a ponieważ wartość jest pojedynczym tokenem leksykalnym, nie potrzebujesz nawiasów wokół niej.zamiast
źródło
#ifdef
jest to, że działa z rzeczami, które nie są zdefiniowane; czy nie zostały zdefiniowane celowo, czy z powodu literówki lub tego, co masz.#if DEBUG_ENBALED
nie jest błędem wykrytym przez preprocesor. JeśliDEBUG_ENBALED
nie jest zdefiniowany, rozwija się do tokenu0
w#if
dyrektywach.Oboje są ohydni. Zamiast tego zrób to:
Następnie, gdy potrzebujesz kodu debugowania, umieść go w środku
D();
. A twój program nie jest zanieczyszczony ohydnymi labiryntami#ifdef
.źródło
#ifdef
po prostu sprawdza, czy dany token jest zdefiniowanynastępnie
źródło
Mieliśmy ten sam problem w wielu plikach i zawsze występuje problem polegający na tym, że ludzie zapominają o dołączeniu pliku z flagą funkcji (przy podstawie kodu> 41 000 plików jest to łatwe).
Jeśli miałeś feature.h:
Ale potem zapomniałeś dołączyć plik nagłówkowy do file.cpp:
Wtedy masz problem, kompilator interpretuje COOL_FEATURE jako niezdefiniowany w tym przypadku jako „fałsz” i nie dołącza kodu. Tak, gcc obsługuje flagę, która powoduje błąd dla niezdefiniowanych makr ... ale większość kodu firm trzecich albo definiuje, albo nie definiuje funkcji, więc nie byłoby to tak przenośne.
Przyjęliśmy przenośny sposób korygowania tego przypadku, a także testowania stanu funkcji: makra funkcji.
jeśli zmieniłeś powyższą funkcję. h na:
Ale potem znowu zapomniałeś dołączyć plik nagłówkowy do file.cpp:
Preprocesor popełniłby błąd z powodu użycia niezdefiniowanego makra funkcji.
źródło
Na potrzeby kompilacji warunkowej #if i #ifdef są prawie takie same, ale nie do końca. Jeśli Twoja kompilacja warunkowa zależy od dwóch symboli, to #ifdef nie będzie działać tak dobrze. Na przykład, załóżmy, że masz dwa symbole kompilacji warunkowej, PRO_VERSION i TRIAL_VERSION, możesz mieć coś takiego:
Użycie #ifdef powyższego staje się znacznie bardziej skomplikowane, zwłaszcza uruchomienie części #else.
Pracuję nad kodem, który intensywnie używa kompilacji warunkowej i mamy mieszankę #if & #ifdef. Zwykle używamy # ifdef / # ifndef dla prostego przypadku i #if, gdy obliczane są dwa lub więcej symboli.
źródło
#if defined
to, codefined
jest to słowo klucz lub?Myślę, że to całkowicie kwestia stylu. Żadna z nich nie ma tak naprawdę oczywistej przewagi nad drugą.
Konsekwencja jest ważniejsza niż którykolwiek konkretny wybór, więc radziłbym zebrać się ze swoim zespołem, wybrać jeden styl i trzymać się go.
źródło
Ja wolę:
Ponieważ znacznie łatwiej jest stworzyć kod, który szuka odwrotnego warunku:
vs.
źródło
#if ! defined
aby uczynić!
bardziej widocznym i trudnym do przeoczenia.To kwestia stylu. Ale polecam bardziej zwięzły sposób zrobienia tego:
Robisz to raz, a następnie zawsze używaj debug_print () do drukowania lub nic nie robisz. (Tak, skompiluje się w obu przypadkach). W ten sposób Twój kod nie zostanie zniekształcony dyrektywami preprocesora.
Jeśli pojawi się ostrzeżenie „wyrażenie nie działa” i chcesz się go pozbyć, oto alternatywa:
źródło
#if
daje możliwość ustawienia go na 0, aby wyłączyć tę funkcję, jednocześnie wykrywając, że przełącznik tam jest.Osobiście zawsze,
#define DEBUG 1
więc mogę to złapać za pomocą #if lub #ifdefźródło
#define DEBUG 1
. Nie#define DEBUG=1
#if i # zdefiniuj MY_MACRO (0)
Użycie #if oznacza, że utworzyłeś makro „zdefiniuj”, czyli coś, co będzie przeszukiwane w kodzie i zostanie zastąpione przez „(0)”. To jest „piekło makr”, którego nienawidzę widzieć w C ++, ponieważ zanieczyszcza kod potencjalnymi modyfikacjami.
Na przykład:
daje następujący błąd na g ++:
Tylko jeden błąd.
Oznacza to, że Twoje makro pomyślnie współdziałało z Twoim kodem C ++: wywołanie funkcji powiodło się. W tym prostym przypadku jest to zabawne. Ale moje własne doświadczenie z makrami grającymi po cichu moim kodem nie jest pełne radości i spełnienia, więc ...
#ifdef i #define MY_MACRO
Używanie #ifdef oznacza, że coś „definiujesz”. Nie znaczy to, że nadajesz mu wartość. Nadal zanieczyszcza, ale przynajmniej zostanie „niczym zastąpiony” i nie będzie postrzegany przez kod C ++ jako instrukcja kodu lagitimate. Ten sam kod powyżej, z prostą definicją, to:
Daje następujące ostrzeżenia:
Więc...
Wniosek
Wolałbym żyć bez makr w swoim kodzie, ale z wielu powodów (definiowanie zabezpieczeń nagłówka lub debugowanie makr) nie mogę.
Ale przynajmniej chcę, aby były one jak najmniej interaktywne z moim legalnym kodem C ++. Oznacza to używanie #define bez wartości, używanie #ifdef i #ifndef (lub nawet #if zdefiniowanego zgodnie z sugestią Jima Bucka), a przede wszystkim nadawanie im nazw tak długich i tak obcych, których nikt o zdrowych zmysłach nie użyje jest to przypadek i w żaden sposób nie wpłynie to na legalny kod C ++.
Post Scriptum
Teraz, gdy ponownie czytam mój post, zastanawiam się, czy nie powinienem próbować znaleźć jakiejś wartości, która nigdy nie będzie poprawna C ++ do dodania do mojego zdefiniowania. Coś jak
który może być użyty z #ifdef i #ifndef, ale nie pozwól na kompilację kodu, jeśli jest używany wewnątrz funkcji ... Próbowałem tego pomyślnie na g ++ i dało to błąd:
Ciekawy. :-)
źródło
To wcale nie jest kwestia stylu. Również pytanie jest niestety błędne. Nie można porównywać tych dyrektyw preprocesora w sensie lepszego lub bezpieczniejszego.
oznacza „jeśli zdefiniowano makro” lub „jeśli makro istnieje”. Wartość makra nie ma tutaj znaczenia. To może być cokolwiek.
jeśli zawsze porównuje się z wartością. W powyższym przykładzie jest to standardowe niejawne porównanie:
przykład użycia #if
teraz możesz umieścić w kodzie definicję CFLAG_EDITION
lub możesz ustawić makro jako flagę kompilatora. Zobacz także tutaj .
źródło
Pierwsza wydaje mi się jaśniejsza. Wydaje się bardziej naturalne, że jest to flaga w porównaniu do zdefiniowanej / nie zdefiniowanej.
źródło
Oba są dokładnie równoważne. W użyciu idiomatycznym #ifdef jest używany tylko do sprawdzenia zdefiniowania (i tego, czego użyłbym w twoim przykładzie), podczas gdy #if jest używany w bardziej złożonych wyrażeniach, takich jak #if zdefiniowane (A) &&! Zdefiniowane (B).
źródło
Trochę OT, ale włączanie / wyłączanie logowania za pomocą preprocesora jest zdecydowanie nieoptymalne w C ++. Istnieją fajne narzędzia do logowania, takie jak log4cxx Apache, które są open-source i nie ograniczają sposobu dystrybucji aplikacji. Pozwalają również na zmianę poziomów rejestrowania bez ponownej kompilacji, mają bardzo niskie narzuty, jeśli wyłączysz wylogowywanie, i dają możliwość całkowitego wyłączenia wylogowywania w środowisku produkcyjnym.
źródło
Kiedyś używałem
#ifdef
, ale kiedy przełączałem się na Doxygen w celu uzyskania dokumentacji, stwierdziłem, że zakomentowanych makr nie można udokumentować (lub przynajmniej Doxygen generuje ostrzeżenie). Oznacza to, że nie mogę udokumentować makr przełączania funkcji, które nie są obecnie włączone.Chociaż możliwe jest zdefiniowanie makr tylko dla Doxygen, oznacza to, że zostaną również udokumentowane makra w nieaktywnych częściach kodu. Osobiście chcę pokazać przełączniki funkcji, a poza tym dokumentować tylko to, co jest aktualnie wybrane. Co więcej, sprawia, że kod jest dość niechlujny, jeśli istnieje wiele makr, które muszą być zdefiniowane tylko wtedy, gdy Doxygen przetwarza plik.
Dlatego w tym przypadku lepiej jest zawsze definiować makra i używać
#if
.źródło
Zawsze używałem #ifdef i flag kompilatora, aby to zdefiniować ...
źródło
Alternatywnie można zadeklarować stałą globalną i użyć języka C ++ if zamiast preprocesora #if. Kompilator powinien zoptymalizować dla Ciebie nieużywane gałęzie, a Twój kod będzie czystszy.
Oto, co C ++ Gotchas autorstwa Stephena C. Dewhursta mówi o używaniu # if's.
źródło
Istnieje różnica w przypadku innego sposobu określenia warunkowego zdefiniowania kierowcy:
wynik:
Oznacza to, że
-DA
jest to synonim-DA=1
wartości, a jeśli wartość zostanie pominięta, może to prowadzić do problemów w#if A
użytkowaniu.źródło
Lubię,
#define DEBUG_ENABLED (0)
gdy potrzebujesz wielu poziomów debugowania. Na przykład:Ułatwia debugowanie wycieków pamięci bez konieczności używania tych wszystkich wierszy dziennika na drodze do debugowania innych rzeczy.
Również
#ifndef
otoczenie definicji ułatwia wybranie określonego poziomu debugowania w wierszu poleceń:Gdyby nie to, dałbym przewagę,
#ifdef
ponieważ flaga kompilatora / tworzenia byłaby nadpisana przez tę w pliku. Nie musisz się więc martwić o zmianę nagłówka z powrotem przed zatwierdzeniem.źródło