2010-10-12 3 views
15

Znalazłem to podczas czytania kodu źródłowego.C++ pusta obsada i przecinek operatora w #define

#define MACRO(x) if((void) 0, (x)); else some_func(); 

Nie rozumiem w pełni przyczyn tego przecinka operatora i pustej obsady. To prawdopodobnie ma coś wspólnego z ochroną makr. Wiem, że (void)0 jest czasami używany do ochrony kaskadowych else s w makrach, takich jak w if(...) then foo(); else (void)0.

Jakieś pomysły, dlaczego występuje przecinek operatora?

edit: Zaczynam myśleć, że to ma coś wspólnego z owl(0,0).

+0

Czy jesteś pewien, że nawet kompiluje? – ronag

+0

@ronag: tak, to kompiluje. Odrzucenie do pustki jest miłym trikiem, jeśli chcesz napisać 'return f();' z funkcji void, gdy 'f' nie jest puste. – ybungalobill

+1

Jestem ciekawy, czy jest to odpowiednik '#define MACRO (X) if (! (X)) {some_func()}' – Arun

Odpowiedz

8

Domyślam się, że trik służy do uniemożliwienia użytkownikowi zadeklarowania zmiennych w stanie if. Jak zapewne wiecie, w C++ jest to legalne to zrobić

if (int i = some_func()) { 
    // you can use `i` here 
} 
else { 
    // and you can use `i` here 
} 

Użycie operatora przecinek w tej definicji spowoduje makro wykorzystanie jak

MACRO(int i = some_func()); 

i zmusić użytkownika do korzystania tylko wyrażeń jako argument.

+0

Masz na myśli 'i' zamiast' x', tak? – sje397

+0

To, co ja, ale zacytować Charlesa, to także tutaj: "... co ((void) 0, x) jest ma chronić przed tym, że prosta dodatkowa para nawiasów nie byłaby, gdyby ((x)), else some_func(); ". – ybungalobill

+0

@ybungalobill: Tak, to prawda ... I dodatkowe'() 'rozwiązałoby to w znacznie prostszy sposób. – AnT

4

Konwersja pustych przestrzeni ma zdecydowanie zapobiec wywołaniu przeciążenia operator ,, ponieważ nie można przeciążać za pomocą parametru void. Gwarantuje to, że (void)0, nie ma wpływu.

Dlaczego jest tam operator przecinka? Dobre pytanie. Naprawdę nie wiem.

+3

Nie rozumiem. Czy możesz wyjaśnić bardziej szczegółowo, co '((void) 0, x)' ma zabezpieczyć przed tym, że prosta dodatkowa para nawiasów nie byłaby 'if ((x)); else some_func(); '? –

+0

@Charles, masz rację. – ybungalobill

2

Wygląda to tak, jakby ktoś mógł rozpocząć pracę z kodem, który zawierał assert, wstępnie przetworzyć go i przekształcić wynik w makro. Po zdefiniowaniu NDEBUG, assert musi zmienić się w prawie nic - ale syntaktycznie nadal musi wygenerować kod zastępczy. Na przykład, masz prawo go używać w sytuacji, takich jak:

assert(x), *x = 1; 

Podczas kompilowania to z NDEBUG zdefiniowany, to nadal musi skompilować, ale assert nie powinien nic robić. Aby wesprzeć że assert definiuje się zazwyczaj coś takiego:

#undef assert 
#ifdef NDEBUG 
#define assert(x) ((void)0) 
#else 
#define assert(x) ((!!x) || __failassert(x, __FILE__, __LINE__)) 
#endif 

Tak więc, jeśli ktoś zaczął z kodem jak wyżej, a następnie spojrzał w wersji wstępnie przetworzonej (z NDEBUG zdefiniowane), że widzą coś takiego:

... a jeśli nie rozumieli kodu bardzo dobrze, mogliby pomyśleć, że ((void)0) naprawdę znaczyło/coś osiągnęło.

+0

Dobre uzasadnienie, ale nie jestem pewien, czy to prawdziwy powód. –

+0

Nie jestem * pewny * to jest prawdziwy powód - w rzeczywistości prawdopodobnie nikt inny, oprócz oryginalnego autora, nie może nic zrobić, ale zgadnie, a nawet on może nie pamiętać na pewno ... –

+0

to "szalone" działa z oryginalnym MACRO: #define CRAZY 0)); if ((1 – user396672