2009-08-17 11 views
5

Czy można zdefiniować makro C/C++ "BUILD(a, i)", które rozwija się do "x[0], x[1], x[2], ..., x[i]"? Podobnie jak w przypadku:Ekspansja cykliczna makra do sekwencji

#define BUILD(x, 0) x[0] 
#define BUILD(x, 1) x[0], x[1] 
#define BUILD(x, 2) x[0], x[1], x[2] 
... 

Wygląda na to, że BOOST_PP_ENUM_PARAMS może wykonać zadanie. Przypuszczam, że mogłem po prostu #include boost, ale jestem zainteresowany wiedzą jak i dlaczego to działa, każdy może wyjaśnić?

ja jak wywołanie funkcji f(int, ...) który zajmuje N int argumentów x[i], 0 < = I < N. gdzie N jest znany jako ceil(sizeof(A)/sizeof(B)). Więc niestety nie mogę używać varargs lub szablonów.

+0

pokrewne: http://stackoverflow.com/questions/824639/variadic-recursive-preprocessor-macros-is-it-possible/893684 –

+0

Jaki problem naprawdę stara się rozwiązać? to znaczy. do czego będzie użyty wynik tego makra? Czy użycie może zostać nieco zmienione, aby umożliwić rozwiązanie szablonu (gdzie rekurencja jest możliwa)? –

+0

Zobacz moją ostatnią zmianę. –

Odpowiedz

14

Jest to możliwe, ale musisz wykonać pewne prace ręczne i mieć górny limit.

#define BUILD0(x) x[0] 
#define BUILD1(x) BUILD0(x), x[1] 
#define BUILD2(x) BUILD1(x), x[2] 
#define BUILD3(x) BUILD2(x), x[3] 
#define BUILD(x, i) BUILD##i(x) 

i zauważ, że i powinna być liczbą całkowitą dosłowny, a nie stałą wartość wyliczona.

BTW, preprocesor jest silniejszy niż zwykle, ale użycie tej mocy jest dość trudne. Boost zapewnia bibliotekę, która ułatwia niektóre rzeczy, w tym iterację. Zobacz Boost Preprocessor Library. Jest jeszcze inna biblioteka takich rzeczy, ale w tej chwili wymyka się ona mojej nazwie.

Edytuj: Biblioteka preprocesora boost używa podobnej techniki. Dzięki dodatkowym sztuczkom pozwalającym rozwiązać problemy z niektórymi narożnikami, udostępniaj makra implementacyjne między obiektami wyższego poziomu, pracuj nad błędami kompilatorów, itp ... zwykłą złożonością wzmocnienia, która jest normalna w kontekście biblioteki ogólnego przeznaczenia, ale która czasami uniemożliwia łatwe zrozumienie zasady wdrażania. Prawdopodobnie najbardziej zauważalną sztuczką jest dodanie poziomu pośredniego, więc jeśli drugi parametr może być makrem, zostanie on rozwinięty. To znaczy. z

#define BUILD_(x, i) BUILD##i(x) 
#define BUILD(x, i) BUILD_(x, i) 

można nawiązać połączenie

#define FOO 42 
BUILD(x, FOO) 

co nie jest możliwe z tym, co narażone.

+0

Dzięki, ciekawe jak BUILD1..BUILD3 są prawie identyczne ... nie mogłem mieć coś takiego jak #define BUILD_ (x, j) BUILD_ (x, j-1), x [j] –

+0

Nie miałoby warunek zatrzymania, a makra nie mogą rekurencyjnie uruchamiać. – Blindy

+0

+1 za miłe wyjaśnienie! –

2

Nie, nie jest - makra nie mogą być rekurencyjne. A makra, które opublikowałeś , nie są wariantowe, co oznacza "posiadanie innej liczby parametrów".

+1

Dzięki, usunąłem tag variadic. –

0

Ok, Miałem ten sam problem, moim celem było wydrukowanie wszystkich wartości tablicy N bajtów za pomocą makr. Zakładam, że miałeś podobny problem. Jeśli tak było, to rozwiązanie powinno odpowiadać przyszłym podobnym problemom.

#define HEX_ARRAY_AS_STR(array, len) \ 
    ({ \ 
     int print_counter = 0; \ 
     print_buf = calloc(len*3+1, 1); \ 
     char *tmp_print_buf = print_buf; \ 
     uint8_t *array_flower = array; \ 
     while(print_counter++ < (len)){ \ 
      sprintf(tmp_print_buf, "%02X ", *(array_flower)++); \ 
      tmp_print_buf += 3; \ 
     } \ 
     print_buf; \ 
    }) 

#define eprintf(...) \ 
    do{ \ 
     char *print_buf; \ 
     printf(__VA_ARGS__); \ 
     if(print_buf) \ 
      free(print_buf); \ 
    }while(0) 

int 
main(int argc, char *argv[]) 
{ 
    uint8_t sample[] = {0,1,2,3,4,5,6,7}; 
    eprintf("%s\n", HEX_ARRAY_AS_STR(sample, 8)); 
    return 0; 
} 
+0

Nie, to nie jest to, co próbowałem zrobić. W każdym razie, jeśli zawsze przekażesz tablicę do HEX_ARRAY_AS_STR możesz pozbyć się drugiego parametru za pomocą sizeof (array)/sizeof (uint8_t) –

Powiązane problemy