2013-09-25 11 views
11

Czy istnieje sposób napisania makra preprocesora C, które rozwija się do różnych rzeczy w zależności od tego, jaki argument otrzymuje?Czy jest możliwe umieszczenie warunku preprocesora wewnątrz makra C?

#define foo() ??? 

/* 1 */ 
foo(name) 

/* 2 */ 
foo(_) 

Pożądany wynik:

/* 1 */ 
int name; 

/* 2 */ 
/*ignore*/ 

Tak, wiem, że makra są złe. Pytam to głównie z ciekawości.

+12

Makra są niesamowite. –

+2

Czy możesz wyjaśnić cel, a może dać lepszy przykład? Parametr musiałby zostać ustalony w czasie kompilacji, co oznacza, że ​​równie dobrze można użyć dwóch różnych nazw makr. – lurker

+0

@mbratch: W tym konkretnym przypadku używam makra do zdefiniowania zestawu zmiennych, ale niektóre zmienne są opcjonalne i chcę uniknąć ich definiowania. Wiele nazw makr nie działałoby dobrze ze względu na kombinatoryczną eksplozję: przy dwóch nazwach zmiennych potrzebowałbym osobnych makr dla 'foo (a, b)', 'foo (a, _)', 'foo (_, b)' oraz ' foo (_, _) '. – hugomg

Odpowiedz

8

Być może spróbuj kilkuetapowej ekspansji makr? Jest to strategia używana przez Boost preprocessor/control/if library.

Nie sądzę, że istnieje sposób sprawdzenia warunków w rozszerzeniu makr C.

Najlepszą rzeczą jaką mogę wymyślić jest zamienienie argumentów makra na literał łańcuchowy za pomocą operatora naciągania #, a następnie sprawdzenie za pomocą funkcji wykonawczych. (To nie będzie działać w Twoim przypadku, chociaż, gdzie chcesz deklaracji zmiennych wyjściowych.)

na przykład następujące drukuje „011”:

#define FOO(x) (strcmp("NAME", #x) ? 1 : 0) 

main() 
{ 
    printf("%d", FOO(NAME)); 
    printf("%d", FOO(1)); 
    printf("%d", FOO(2)); 
} 

Kompilator najprawdopodobniej optymalizacji strcmp porównań podczas kompilacji, więc nie byłoby to bardziej nieefektywne, niż gdyby dostępne były prawdziwe warunki wstępne procesora. Jednak wykonanie normalnej funkcji byłoby bardziej przejrzyste i prawdopodobnie równie skuteczne.

+0

Interesująca sztuczka! Ale czy istnieje sposób, w którym nie muszę wyliczać wszystkich możliwości dla przypadku "1"? Na przykład jeśli jego '_' to makro daje 2, jeśli cokolwiek innego daje 1? – hugomg

+0

Zaktualizowałem swoją odpowiedź, stosując ograniczone obejście problemu, które nie zadziała w przypadku pierwotnego pytania. –

+0

Niestety, nie mogę użyć testu środowiska wykonawczego w moim przypadku. Zaczynam myśleć, że pierwsze rozwiązanie, w które grasz, jest najlepsze, jakie dostanę. – hugomg

8

Aby rozwinąć na odpowiedź Gavina Smitha, to rzeczywiście może sprawdzić warunki w makr:

#define FOO_name 1 
#define FOO__ 0 

#define CONC(a,b) a##_##b 

#define IF(c, t, e) CONC(IF, c)(t, e) 
#define IF_0(t, e) e 
#define IF_1(t, e) t 

#define FOO(x) IF(CONC(FOO,x), int x;,) 

FOO(name) // -> int name; 
FOO(_) // -> /*nothing*/ 

Jeśli czujesz się na siłach można łatwo rozszerzyć IF aby umożliwić przecinki, tłumić makro ekspansję itd z makra pomocnicze.

Jak wyżej, wymaga to wcześniejszej znajomości wszystkich żądanych nazw.

Powiązane problemy