Porównanie makr według dyrektywy

25

Dlaczego #ifspełniono warunek w następującym kodzie:

#include <iostream>
#define VALUE foo    

int main() {    
#if VALUE == bar
    std::cout << "WORKS!" << std::endl;
#endif // VALUE
}
michalt38
źródło

Odpowiedzi:

26

Strona na cppreference.com stanów:

Po całym rozwinięciu makra i ocenie zdefiniowanych i __has_include (od C ++ 17) każdego identyfikatora, który nie jest literałem logicznym, zastępuje się liczbą 0 (obejmuje to identyfikatory, które są leksykalnie słowami kluczowymi, ale nie są to alternatywne tokeny, takie jak i ).

Więc oba fooi barsą zastępowane 0.

BessieTheCow
źródło
Co z C ++ 98, C ++ 03, C ++ 11 i C ++ 14?
kelalaka
1
@kelalaka Wszystko jest takie samo. Tak było od C89.
SS Anne
1
@kelalaka „Od C ++ 17” odnosi się tylko do części „i __has_include”. Przed C ++ 17 było tak samo, tylko z tą częścią pominiętą.
BessieTheCow
15

W #ifinstrukcji każdy identyfikator pozostały po podstawieniu makra (z wyjątkiem truei false) jest zastępowany stałą 0. Twoja dyrektywa staje się

#if 0 == 0

co jest prawdą.

1201ProgramAlarm
źródło
Aby to wyjaśnić, „#define VALUE foo” definiuje symbol „VALUE”, aby uzyskać taką samą wartość jak symbol „foo”, ale symbol „foo” nie ma znaczenia, więc zostanie zinterpretowany jako 0.
ManicDee
13

Wynika to z faktu, że ani foonie barpodano żadnej definicji, ani wartości - więc są one takie same (tj. Zastąpione wartością „0”). Kompilatory wydadzą ostrzeżenia o tym.

MSVCKompilator (Visual Studio 2019) podaje następujące elementy:

ostrzeżenie C4668: „foo” nie jest zdefiniowane jako makro preprocesora, zastępowane przez „0” dla „# if / # elif”
ostrzeżenie C4668: „pasek” nie jest zdefiniowane jako makro preprocesora, zastępowane przez „0” dla „#if / # elif ”

Tak więc VALUEotrzymuje wartość „0” (domyślnie dla foo), a bartakże ma „0”, więc VALUE == barocenia się na „PRAWDA”.

Podobnie clang-cldaje następujące:

ostrzeżenie: „foo” nie jest zdefiniowane, ocenia na 0 [-Wundef]
ostrzeżenie: „bar” nie jest zdefiniowane, ocenia na 0 [-Wundef]

Adrian Mole
źródło
Czy ostrzeżenie jest obowiązkowe, czy jest funkcją kompilatorów?
kelalaka
1
@kelalaka Według mojej najlepszej wiedzy, żadne „ostrzeżenia” kompilatora nie są obowiązkowe! Nawet z MSVCi clang-clkompilatory, to ostrzeżenie może być wyłączona (albo specjalnie, albo przez ustawienie odpowiedniego ostrzeżenia „poziom”).
Adrian Mole
0

Aby osiągnąć to, czego szukasz, spróbuj:

#include <iostream>
#define DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

W takim przypadku możesz wyłączyć instrukcje debugowania, zmieniając „defin” na „undef”.

#include <iostream>
#undef DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Może się okazać, że twój kompilator pozwala ci zdefiniować DEBUGĘ poza samym kodem, w którym to momencie możesz zredukować kod

#include <iostream>

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Następnie uruchom kompilator z opcją taką jak -DDEBUG = 0

Sprawdź rozdział dotyczący programowania defensywnego w Steve McConnell, „Kod zakończony”.

ManicDee
źródło