2012-02-08 16 views
14

Zdefiniowałem kilka makr, które ułatwiają definiowanie tablicy struktur, ale nie mogę znaleźć sposobu na ich użycie bez generowania błędów. Oto makra (i kilka przykładowych struktur w celu wykazania, dlaczego mogą być wykorzystywane makra (rzeczywiste struktury Ja zaludniając są trochę bardziej skomplikowane)):Jak mam przecinek wewnątrz nawiasu wewnątrz argumentu makra, gdy nawiasy powodują błąd składni?

struct string_holder { 
    const char *string; 
}; 
struct string_array_holder { 
    struct string_holder *holders; 
}; 
#define DEFINE_STRING_ARRAY_HOLDER(name, values) \ 
    static struct string_holder name##__array[] = values; \ 
    static struct string_array_holder name = { name##__array } 
#define WRAP_STRING(string) { string } 

Współpracuje tylko podczas korzystania to zadeklarować tablicę z jednej pozycji:

DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, { 
    WRAP_STRING("my string") 
}); 

Ale kiedy korzystać z wielu elementów:

DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, { 
    WRAP_STRING("hello"), 
    WRAP_STRING("world") 
}); 

otrzymuję ten błąd:

error: too many arguments provided to function-like macro invocation

Interpretacja przecinka w nawiasach klamrowych jako separatora argumentów. Śledzę porady od this question i umieścić nawiasy wokół problematycznej argumentu:

DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, ({ 
    WRAP_STRING("hello"), 
    WRAP_STRING("world") 
})); 

Teraz, gdy próbuję go skompilować, interpretuje ({ ... }) jako statement expression i narzeka:

warning: use of GNU statement expression extension
(a bunch of syntax errors resulting from its interpretation as a statement expression)
error: statement expression not allowed at file scope

Jak mogę albo:

  • pomocą makra bez błędów (korzystnie) lub
  • t przepisywania on jest makro [s] do pracy w tych okolicznościach?
+0

Co z makrami variadic? Zobacz: http://stackoverflow.com/q/679979/929459 – Dmitri

Odpowiedz

13

Dmitri ma rację, variadic macros to droga.

kładę jakiś przykładowy kod używać do sprawdzania, czy dany klucz jest członkiem listy wartości:

#define _IN(KEY, ...)            \ 
({                \ 
    typedef __typeof (KEY) _t;          \ 
    const _t _key = (KEY);           \ 
    const _t _values[] = { __VA_ARGS__ };       \ 
    _Bool _r = 0;             \ 
    unsigned int _i;            \ 
    for (_i = 0; _i < sizeof (_values)/sizeof (_values[0]); ++_i) \ 
    if (_key == _values[_i])          \ 
     {               \ 
     _r = 1;             \ 
     break;             \ 
     }               \ 
    _r;                \ 
}) 

umysł wykorzystanie __VA_ARGS__.

Aktualizacja: surowego roztworu, jeśli nie podoba __VA_ARGS__ w dowolnych miejscach byłoby „unwrapper” makro:

#define UNWRAP(...) __VA_ARGS__ 

Można używać go jak prefix-operatora. ;-)

#include <stdio.h> 

/* "unwrapper": */ 
#define UNWRAP(...) __VA_ARGS__ 

/* your macros: */ 
#define WRAP(NAME, ELEMS) static const char *NAME[] = { UNWRAP ELEMS } 

int 
main (void) 
{ 
    WRAP (some_test, ("a", "b", "c")); 
    printf ("The second elem in some_test is: '%s'\n", some_test[1]); 
    return 0; 
} 
+3

W rzeczywistości, rzecz 'UNWRAP' jest schludna. Dzięki! – icktoofay

1

Tak, użyj __VA_ARGS__, ale Kay „s solution jest zbyt skomplikowana. Wystarczy:

#define DEFINE_STRING_ARRAY_HOLDER(name, ...)     \ 
    static struct string_holder name##_array[] = __VA_ARGS__; \ 
    static struct string_array_holder name = { name##_array } 

wystarcza. Możesz wtedy użyć tego makra tak, jak zamierzałeś:

DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, { 
    WRAP_STRING("hello"), 
    WRAP_STRING("world") 
});