2009-08-17 11 views
5

Kann ein C/C++ - Makro "BUILD(a, i)" definiert werden, das auf "x[0], x[1], x[2], ..., x[i]" erweitert wird? Wie inMakro-rekursive Erweiterung zu einer Sequenz

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

Es scheint, BOOST_PP_ENUM_PARAMS könnte den Job machen. Ich nehme an, ich könnte nur Boost hinzufügen, aber ich bin daran interessiert zu wissen, wie und warum es funktioniert, kann jeder erklären?

Ich mag würde eine Funktion f(int, ...) aufzurufen, die Argumente N int nimmt x[i], 0 < = i < N. Wo N bekannt ist ceil(sizeof(A)/sizeof(B)) zu sein. Daher kann ich leider keine Varargs oder Templates verwenden.

+0

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

+0

Welches Problem haben Sie wirklich zu lösen versuchen? dh. Wofür wird das Ergebnis dieses Makros verwendet? Kann die Verwendung leicht geändert werden, um eine Vorlagenlösung zu ermöglichen (wo Rekursion möglich ist)? –

+0

Siehe meine letzte Änderung. –

Antwort

14

Es ist möglich, aber Sie müssen einige manuelle Arbeit tun und haben eine Obergrenze.

#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) 

Und beachten Sie, dass i sollte ein Ganzzahlliteral sein, keine Konstante berechneten Wert.

BTW, der Präprozessor ist leistungsfähiger als was normalerweise ist, aber die Verwendung dieser Macht ist ziemlich schwierig. Boost bietet eine Bibliothek, die einige Dinge erleichtert, einschließlich Iteration. Siehe Boost Preprocessor Library. Es gibt eine andere Bibliothek für solche Dinge, aber der Name entzieht sich mir im Moment.

Bearbeiten: Die Boost Preprocessor-Bibliothek verwendet eine ähnliche Technik. Mit zusätzlichen Tricks, um einige Probleme mit Eckenfehlern zu lösen, teilen Sie Implementierungsmakros zwischen Einrichtungen auf höherer Ebene, umgehen Compilerfehler, etc ... die übliche Boost-Komplexität, die im Kontext einer allgemeinen Bibliothek normal ist, aber zuweilen ein einfaches Verständnis davon verhindert die Umsetzungsprinzipien. Der wahrscheinlich auffälligste Trick besteht darin, eine Indirektionsstufe hinzuzufügen, so dass, wenn der zweite Parameter ein Makro sein kann, dieser erweitert wird. I.e. mit

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

kann man den Anruf

#define FOO 42 
BUILD(x, FOO) 

, die mit nicht möglich ist, was ich ausgesetzt.

+0

Danke, es ist interessant, wie BUILD1..BUILD3 fast identisch sind ... könnte ich nicht etwas wie #define haben BUILD_ (x, j) BUILD_ (x, j-1), x [j] –

+0

hätte es nicht eine Stoppbedingung, und Makros können nicht rekursiv zum Booten sein. – Blindy

+0

+1 für eine nette Erklärung! –

2

Nein, es ist nicht - Makros können nicht rekursiv sein. Und die von Ihnen geposteten Makros sind nicht variadisch, was bedeutet, dass "unterschiedliche Anzahlen von Parametern" vorhanden sind.

+1

Danke, ich habe das variadic-Tag entfernt. –

0

Ok, Ich hatte das gleiche Problem, Mein Ziel war es, alle Werte eines Arrays von N Bytes mit Makros zu drucken. Ich nehme an, Sie hatten das gleiche Problem. Wenn dies der Fall ist, sollte diese Lösung zukünftigen ähnlichen Problemen gerecht werden.

#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

Nein, das habe ich nicht versucht. Wie auch immer, wenn Sie ein Array immer an HEX_ARRAY_AS_STR übergeben, können Sie den zweiten Parameter mit sizeof (array)/sizeof (uint8_t) loswerden –

Verwandte Themen