2010-12-28 14 views
9

Gibt es eine Möglichkeit in Standard-C-oder mit GNU-Erweiterungen - Sachen an eine Makrodefinition anzuhängen? Zum Beispiel, ein Makro definiert als
#define List foo bar
kann ich bas so anhängen gegeben, dass es List wie erweitert, wenn ich es definiert hatte
#define List foo bar bas?Kann ich an ein Präprozessor-Makro anhängen?

Ich hatte gehofft, ich etwas tun könnte:

#define List foo bar bas 

#define List_ Expand(List) 
#undef List 
#define List Expand(List_) quux 

aber ich kann nicht herausfinden, wie die Expand() Makro zu definieren, so wird es das tun, was ich will.

Motivation: ich mit diskriminiert ich spiele/getaggt Gewerkschaften in diese Richtung:

struct quux_foo { int x; }; 
struct quux_bar { char *s; }; 
struct quux_bas { void *p; }; 

enum quux_type {quux_foo, quux_bar, quux_bas}; 

struct quux { 
    enum quux_type type; 
    union { 
     struct quux_foo foo; 
     struct quux_bar bar; 
     struct quux_bas bas; 
    } t; 
}; 

ich meine, dies ist ein guter Ort für den X-Makro ist. Wenn ich ein Makro
#define quux_table X(foo) X(bar) X(bas)
die Aufzählung & Struktur definieren kann so definiert werden, und nie aus dem Takt geraten:

#define X(t) quux_ ## t, 
enum quux_type {quux_table}; 
#undef X 

#define X(t) struct quux_ ## t t; 
struct quux { 
    enum quux_type type; 
    union {quux_table} t; 
}; 
#undef X 

Natürlich ist die quux_* Strukturen nicht synchron bekommen, so möchte ich so etwas zu tun, nur legal:

struct quux_foo { int x; }; 
#define quux_table quux_table X(foo) 

struct quux_bar { char *s; }; 
#define quux_table quux_table X(bar) 

struct quux_bas { void *p; }; 
#define quux_table quux_table X(bas) 

(Na ja, was ich wirklich in der Lage sein will, ist, etwas zu tun wie
member_struct(quux, foo) { int x; };
aber ich bin mir durchaus bewusst, dass Makros nicht (wieder) definiert aus Makros sein kann.)

Wie auch immer, das ist mein Motivations Beispiel. Gibt es einen Weg, dies zu erreichen?

Boost.Preprocessor Beispiele sind in Ordnung, wenn Sie mir zeigen können, wie die X-Makro-Technik mit dieser Bibliothek arbeiten.

+0

Ja, das ist definitiv machbar, wenn Sie nicht auf Neudefinition bestehen. Etwas schmerzhaft, wenn Sie den rohen Präprozessor verwenden. Etwas weniger schmerzhaft mit Boost.Preprocessor. Ach, meine Erkältung verhindert, dass ich gerade genug nachdenke, um eine Methode zu entwickeln. Hoffentlich wird es jemand anderes tun. – swestrup

Antwort

5

Effektiv, nein.

Makros werden langsam ausgewertet. Wenn Sie #define List_ Expand(List), ist seine Ersatzliste die Reihenfolge der vier Token Expand, (, List und ). Es gibt keine Möglichkeit, ein Makro in eine Ersatzliste zu erweitern.

Der gesamte Makroaustausch findet statt, wenn ein Makro aufgerufen wird.

Ich würde empfehlen, mit der Boost.Preprocessor-Bibliothek für die automatische Code-Generierung zu suchen. Es ist ein bisschen Arbeit, aber Sie können einige fairly impressive things damit erreichen. Es sollte voll kompatibel mit C.

+0

Danke für die Erklärung. –

2

Ich bin mir nicht sicher, ob das hilft, aber Sie können Vari Arg Makros tun. Herr Conrad vom x264-Projekt liebt Präprozessor-Missbrauch. Wenn sie so klingen, als könnten sie Ihnen helfen, können Sie mehr herausfinden Here

+1

C99 variadic Makros sind nett (und ich habe sie verwendet), aber das ist nicht wirklich relevant für meine Frage. (Nicht direkt, zumindest, obwohl ich mir vorstellen kann, dass die tatsächliche Lösung _variable Makros irgendwo verwenden kann.) –

2

Es gibt einen Weg!

das neue _Pragma Schlüsselwort Mit diesem kann (wenn auch nicht mit msvc) in gcc erreicht wird

Wenn Sie einen Makro innerhalb seiner eigenen Definition Pop wird es verzögern Expansion ist, bis das Makro zum ersten Mal erweitert wird. Auf diese Weise können Sie die vorherige Erweiterung zu einer eigenen Definition machen. da es geknallt wird, kann einmal während es Expansion, es verwendet

Hier ist ein Beispielcode, es zu sehen in Aktion wird jedoch nur

#define pushfoo _Pragma("push_macro(\"foo\")") //for convenience 
#define popfoo _Pragma("pop_macro(\"foo\")") 

#define foo 1 

pushfoo       //push the old value 
#undef foo      //so you don't get a warning on the next line 
#define foo popfoo foo , 2  //append to the previous value of foo 

pushfoo 
#undef foo 
#define foo popfoo foo , 3 

pushfoo 
#undef foo 
#define foo popfoo foo , 4 


foo //this whole list will expand to something like popfoo foo popfoo foo popfoo foo , 4 
    //which will in turn expand to 1 , 2 , 3 , 4 

foo //the second time this will expand to just 1 

Diese Option ein gutes Stück einfacher, automatische Codegenerierung obwohl machen sollte leider nur auf gcc (vielleicht klingeln, nicht getestet)

Um ehrlich zu sein gibt es keinen Grund, warum ich finden kann, warum das funktionieren muss, es ist höchstwahrscheinlich undefiniertes Verhalten, das passiert. Ich vermute, der Grund ist, dass nach dem Poppen foo, das aktuelle Makro erweitert wird nicht mehr mit dem Namen foo verbunden ist, die erlaubt das Symbol foo erweitert werden, aber das ist nur meine Vermutung

Verwandte Themen