Co dokładnie robi blok #if 0… #endif?


124

W C / C ++

Co dzieje się z kodem umieszczonym między blokiem #if 0/ #endif?

#if 0

//Code goes here

#endif

Czy kod jest po prostu pomijany, a zatem nie jest wykonywany?


17
Jest to technika używana do komentowania dużych ilości kodu lub umożliwiająca testowanie włączenia bloków kodu. Bez tej funkcji należałoby poprzedzić każdą linię //lub rozpocząć sekcję od /*i zakończyć sekcję */. Problem z tymi ostatnimi technikami polega na tym, że komentarze nie zagnieżdżają się, więc programista musi sprawdzić i obsłużyć każdy */między początkiem a końcem.
Thomas Matthews

Odpowiedzi:


141

Nie tylko nie jest wykonywany, ale nawet nie jest kompilowany.

#ifjest poleceniem preprocesora, które jest oceniane przed właściwym krokiem kompilacji. Kod wewnątrz tego bloku nie pojawia się w skompilowanym pliku binarnym.

Jest często używany do tymczasowego usuwania segmentów kodu z zamiarem ponownego ich późniejszego włączenia.


1
Dotyczy to każdego rodzaju komentarza. Ważną różnicą jest zagnieżdżanie.
Samy Bencherif

73

Jest to identyczne z komentowaniem bloku, z jedną ważną różnicą: zagnieżdżanie nie stanowi problemu. Rozważ ten kod:

foo();
bar(x, y); /* x must not be NULL */
baz();

Jeśli chcę to skomentować, mogę spróbować:

/*
foo();
bar(x, y); /* x must not be NULL */
baz();
*/

Bzzt. Błąd składni! Czemu? Ponieważ komentarze blokowe nie zagnieżdżają się, a więc (jak widać z podświetlania składni SO), */po wyrazie „NULL” kończy komentarz, sprawiając, że bazwywołanie nie jest komentowane, a */po baznim następuje błąd składniowy. Z drugiej strony:

#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif

Działa, aby skomentować całość. A #if 0s zagnieżdżą się ze sobą, w ten sposób:

#if 0
pre_foo();
#if 0
foo();
bar(x, y); /* x must not be NULL */
baz();
#endif
quux();
#endif

Chociaż, oczywiście, może to być nieco zagmatwane i stać się problemem związanym z konserwacją, jeśli nie zostanie odpowiednio skomentowane.


5
Zwróć uwagę, że kod wewnątrz #if musi być poprawny leksykalnie (w przeciwieństwie do komentarzy), a dyrektywy preprocesora nadal obowiązują (jw).
jpalecek

@David: Nie jest poprawne leksykalnie, ale nadal będzie się kompilować. Więc kod nie musi być poprawny leksykalnie.
Dennis Zickefoose

1
@Dennis, mam foo.c:3: unterminated string or character constantod gcc, czego używasz?
David X

18

Trwale komentuje ten kod, więc kompilator nigdy go nie skompiluje.

Koder może później zmienić #ifdef, aby kod został skompilowany w programie, jeśli zechce.

Dokładnie tak, jakby kod nie istniał.


14

Co dokładnie robi blok #if 0… #endif?

Mówi ci, że autor oczywiście nigdy nie słyszał o systemie kontroli wersji. Co z kolei każe ci uciekać jak najdalej…


12

Chciałbym dodać do #elsesprawy:

#if 0
   /* Code here will NOT be complied. */
#else
   /* Code will be compiled. */
#endif


#if 1
   /* Code will be complied. */
#else
   /* Code will NOT be compiled. */
#endif

7

Gdy preprocesor widzi #if, sprawdza, czy następny token ma wartość niezerową. Jeśli tak, zachowuje kod kompilatora. Jeśli tak się nie stanie, pozbywa się tego kodu, więc kompilator nigdy go nie widzi.

Jeśli ktoś powie #if 0, skutecznie komentuje kod, więc nigdy nie zostanie skompilowany. Możesz myśleć o tym tak samo, jakby umieścili / * ... * / wokół niego. To nie jest to samo, ale daje ten sam efekt.

Jeśli chcesz dokładnie zrozumieć, co się stało, często możesz spojrzeć. Wiele kompilatorów pozwoli ci zobaczyć pliki po uruchomieniu preprocesora. Na przykład w programie Visual C ++ polecenie switch / P uruchomi preprocesor i umieści wyniki w pliku .i.


Nie do końca. Preprocesor analizuje według wiersza, a nie tokenu. Zgodnie z twoim wyjaśnieniem nie byłoby możliwe powiedzieć, na przykład, #if WIN32 || __CYGWIN__ale to działa zgodnie z oczekiwaniami.
Ben Voigt

Upraszczałem. Jeśli występuje lub, sprawdzi, czy którykolwiek token jest różny od zera. Podobnie, jeśli istnieje i sprawdzi, czy oba są niezerowe.
Steve Rowe

3

Linie zaczynające się od a #dyrektywami preprocesora . #if 0 [...] #endifbloki nie docierają do kompilatora i nie generują kodu maszynowego.

Możesz zademonstrować, co dzieje się z preprocesorem za pomocą pliku źródłowego ifdef.cxx:

#if 0
This code will not be compiled
#else
int i = 0;
#endif

Bieganie gcc -E ifdef.cxx pokaże ci, co zostanie skompilowane.

Możesz użyć tego mechanizmu, aby zapobiec kompilacji bloku kodu podczas cyklu rozwoju, ale prawdopodobnie nie chcesz sprawdzać go w kontroli źródła, ponieważ po prostu dodaje on cruft do twojego kodu i zmniejsza czytelność. Jeśli jest to historyczny fragment kodu, który został wykomentowany, należy go usunąć: kontrola źródła zawiera historię, prawda?

Również odpowiedź może być taka sama dla C i C ++, ale nie ma języka o nazwie C / C ++ i nie jest dobrym nawykiem odwoływanie się do takiego języka.


4
Co jest złego w mówieniu C / C ++ jako skrótu dla „C lub C ++”? Czy naprawdę myślisz, że ktoś pomyli się myśląc, że istnieje język o nazwie „C / C ++”?
Christopher Barber

1
@Chris: Ludzie stale zadają pytania typu „Jak zrobić X w C / C ++?” To jest bezsensowne pytanie; kodujesz w jednym lub drugim, a jeśli jeszcze nie wybrałeś, powinieneś to wyraźnie powiedzieć. Więc tak, ludzie są zdezorientowani, że istnieje język o nazwie „C / C ++”
Dennis Zickefoose

1
Co za bezsensowne stwierdzenie! Istnieją tysiące pytań, na które odpowiedzi dotyczą zarówno C, jak i C ++. Pamiętaj, że to jest strona do zadawania pytań. To, że zadajesz ogólne pytanie, nie oznacza, że ​​nie wiesz, jakiego języka używasz. Jeśli podejrzewasz, że tak jest, jak w tym pytaniu, w jaki sposób może pomóc określenie C lub C ++? Czy uważasz, że byłoby pomocne, gdyby każde pytanie, które może dotyczyć C lub C ++, zostało zadane dwukrotnie?
Christopher Barber

@Christopher: Masz rację, jest wiele pytań, w których odpowiedzi są równie istotne dla C, C ++ i Objective-C (to jest jedno z nich). Stack Overflow ma wygodny system tagowania, aby wskazać, do jakich języków należy pytanie. Jak wspomina @Dennis, SO (i inne fora programistyczne [fora?]) Jest (zbyt) wielu ludzi, którzy są zdezorientowani co do rozgraniczenia między C a innymi językami wywodzącymi się z języka C, którzy nazywają te języki zamiennie C / C ++, dzięki czemu trudniej odpowiedzieć na pytanie w odpowiednim języku.
Johnsyweb

2

Nie do końca

int main(void)
{
   #if 0
     the apostrophe ' causes a warning
   #endif
   return 0;
}

Pokazuje "tc: 4: 19: ostrzeżenie: brak znaku kończącego" z gcc 4.2.4


2
To ostrzeżenie jest generowane przez preprocesor, a nie kompilator. Kompilator widzi tylko: # 1 "tc" # 1 "<built-in>" # 1 "<command-line>" # 1 "tc" int main (void) {return 0; }
Johnsyweb

0

Jest to tani sposób komentowania, ale podejrzewam, że może mieć potencjał debugowania. Na przykład załóżmy, że masz kompilację, która wyprowadza wartości do pliku. Możesz nie chcieć tego w ostatecznej wersji, więc możesz użyć #if 0 ... #endif.

Podejrzewam też, że lepszym sposobem zrobienia tego w celu debugowania byłoby:

#ifdef DEBUG
// output to file
#endif

Możesz zrobić coś takiego i może to mieć więcej sensu, a wszystko, co musisz zrobić, to zdefiniować DEBUG, aby zobaczyć wyniki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.