2016-06-16 15 views
7

* Nicht zu verwechseln mit Assoziativen Arrays.Aufrufen einer assoziativen * Funktion mit C-Makros

Ich weiß, wie man eine Funktion in C mit Makros vektorisiert, um Ergebnisse ähnlich der Mathematica Map (oder Apply) -Funktionalität zu geben. Nämlich eine Funktion auf eine Liste von Argumenten anwenden.

#define Apply(type, function, ...)    \ 
{            \ 
    void *Stop = (int[]){0};      \ 
    type **List = (type*[]){__VA_ARGS__, Stop}; \ 
    for(int i = 0; List[i] != Stop; ++i)  \ 
    function(List[i]);       \ 
}      

Ich kann dann wie

etwas tun
#define FreeAllAtOnce(...) Apply(void, free, __VA_ARGS__); 

, die die Wirkung hat, dass

free(Array1); 
free(Array2); 
free(Array3); 

zu

FreeAllAtOnce(Array1, Array2, Array3); 

ich, dass nicht machen up entspricht, Ich habe darüber in einem Buch gelesen und habe es h benutzt seither.

Meine Frage ist: Kann ich etwas Ähnliches tun, um ein Array über einige Binärfunktionen assoziativ zu kombinieren. Nehmen Sie zum Beispiel die GCD-Funktion. Ich möchte eine Funktion wie:

GCD_all(a, b, c, d, e); 

, dass die gleiche Wirkung wie

GCD(GCD(GCD(GCD(a, b), c), d), e); 

für eine beliebige Anzahl von Argumenten hat.

Ich habe versucht, dies zu tun und war nicht in der Lage, es richtig funktionieren zu lassen. Ich bin auch an dem Fall interessiert, bei dem zusätzliche Parameter an die Funktion übergeben werden können. Im allgemeinsten Sinne freue ich dies wie mit Funktionen zu tun:

Atype BinaryCombine(Atype a, Atype b, OtherType z, OtherType y) 

, so dass ich eine Funktion haben

Atype BinaryCombineAll(Atype a, Atype b, Atype c, Atype d, OtherType z, OtherType y) 

Ich hoffe, das macht Sinn. Irgendwelche Ideen oder Hilfe würden sehr geschätzt!

Danke.

+0

Ich denke, Sie hätten etwas Erfolg mit C++ 11 variadic Vorlagen haben können – ForceBru

+0

BTW, wie willst du herausfinden, wie viele Argumente 'Funktion' dauern kann? – ForceBru

+0

@ForceBru, ich bin daran interessiert, in C zu bleiben. In meinem ersten Beispiel Funktion nur ein Argument. Wonach ich frage, ist eine, die zwei (oder mehr) braucht. – amcalde

Antwort

2

Dies erfordert eher heikel Maschinen (siehe diese answer für weitere Details), da man normalerweise nicht rekursive Makros in C haben:

int main(void) 
{ 
    GCD(GCD(GCD(GCD(a, b), c), d), e); 
} 

Die NUM_ARGS:

#define _NUM_ARGS2(X,X5,X4,X3,X2,X1,N,...) N 
#define NUM_ARGS(...) _NUM_ARGS2(0,__VA_ARGS__,5,4,3,2,1,0) 
// be sure to add X6,X7,... and 6,7,... to support more arguments 

#define GCD_OF_1(a)   (a)   
#define GCD_OF_2(a,b)  GCD(a, b) 
#define GCD_OF_3(a,b,...) GCD_OF_2(GCD_OF_2(a,b),__VA_ARGS__) 
#define GCD_OF_4(a,b,...) GCD_OF_3(GCD_OF_2(a,b),__VA_ARGS__) 
#define GCD_OF_5(a,b,...) GCD_OF_4(GCD_OF_2(a,b),__VA_ARGS__) 
// in general: 
// #define GCD_OF_N(a,b,...) GCD_OF_N-1(GCD_OF_2(a,b),__VA_ARGS__) 

#define _GCD_OF_N3(N, ...) GCD_OF_ ## N(__VA_ARGS__) 
#define _GCD_OF_N2(N, ...) _GCD_OF_N3(N, __VA_ARGS__) // helper macro to expand N 
#define GCD_all(...)  _GCD_OF_N2(NUM_ARGS(__VA_ARGS__), __VA_ARGS__) 

int main(void) 
{ 
    GCD_all(a, b, c, d, e); 
} 

Die gcc -E Ausgabe als produziert findet automatisch die Anzahl der Argumente. Auf diese Weise erhalten Sie das Makro "Startpunkt" GCD_OF_N für die weitere Erweiterung.

+0

Danke. Es sieht so aus, als müssten Sie all diese Makros im Voraus ausführen und jeden möglichen Fall von Eingaben abdecken. Ich dachte über einen anderen Weg nach, aber es erfordert alle Eingaben als Zeiger, nicht als Daten. – amcalde

Verwandte Themen