Frage

Ich habe in ein kleines theoretisches Problem laufen. In einem Stück Code, den ich Aufrechterhaltung gibt es eine Reihe von Makros wie

#define MAX_OF_2(a, b)       (a) > (b) ? (a) : (b)
#define MAX_OF_3(a, b, c)    MAX_OF_2(MAX_OF_2(a, b), c)
#define MAX_OF_4(a, b, c, d) MAX_OF_2(MAX_OF_3(a, b, c), d)
...etc up to MAX_OF_8

Was ich möchte, ist sie wie folgt mit etwas tun, ersetzen:

/* Base case #1, single input */
#define MAX_OF_N(x)      (x)

/* Base case #2, two inputs */
#define MAX_OF_N(x, y)   (x) > (y) ? (x) : (y)

/* Recursive definition, arbitrary number of inputs */
#define MAX_OF_N(x, ...) MAX_OF_N(x, MAX_OF_N(__VA_ARGS__))

... was natürlich ist nicht gültig Präprozessor Code.

ignorierend, dass dieser spezielle Fall soll wohl eine Funktion anstatt eine Präprozessormakro gelöst wird mit , ist es möglich, ein variadische MAX_OF_N () Makro definieren?

Nur für Klarheit sollte das Endergebnis ein einzelnes Makro sein, die zu den größten von ihnen, eine beliebige Anzahl von Parametern und auswertet nimmt. Ich habe ein seltsames Gefühl, dass dies möglich sein soll, aber ich bin nicht zu sehen, wie.

War es hilfreich?

Lösung

Nein, weil der Präprozessor dauert nur eine „Swipe“ an der Datei. Es gibt keine Möglichkeit, es zu erhalten, um rekursiv Makros zu definieren.

Der einzige Code, dass ich etwas tun gesehen habe, wie dies war nicht variadische, sondern verwendet die Standardwerte der Benutzer hatte weitergeben müssen:

x = MAX_OF_8 (a, b, -1, -1, -1, -1, -1, -1)

vorausgesetzt, alle Werte waren nicht-negativ ist.

Inline-Funktionen sollten Ihnen das gleiche gibt für C ++ zumindest. Wie Sie feststellen, ist es wahrscheinlich besser links auf eine Funktion mit variabler Argumente ähnlich wie printf().

Andere Tipps

Es ist möglich, ein Makro zu schreiben, die auf die Anzahl der Argumente wertet sie mit genannt wird. (Ich konnte keine Verbindung zu dem Ort, wo ich es zum ersten Mal sah.) So könnte man schreiben MAX_OF_N () dass das funktionieren würde, wie Sie möchten, aber Sie würden immer noch müssen alle nummerierten Makros, bis irgendeine Grenze bis:

#define MAX_OF_1(a)         (a)         
#define MAX_OF_2(a,b)       max(a, b)

#define MAX_OF_3(a,...)    MAX_OF_2(a,MAX_OF_2(__VA_ARGS__))
#define MAX_OF_4(a,...)    MAX_OF_2(a,MAX_OF_3(__VA_ARGS__))
#define MAX_OF_5(a,...)    MAX_OF_2(a,MAX_OF_4(__VA_ARGS__))
...
#define MAX_OF_64(a,...)   MAX_OF_2(a,MAX_OF_63(__VA_ARGS__))

// NUM_ARGS(...) evaluates to the literal number of the passed-in arguments.
#define _NUM_ARGS2(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

#define _MAX_OF_N3(N, ...) MAX_OF_ ## N(__VA_ARGS__)
#define _MAX_OF_N2(N, ...) _MAX_OF_N3(N, __VA_ARGS__)
#define MAX_OF_N(...)      _MAX_OF_N2(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

Jetzt wird MAX_OF_N(a,b,c,d,e) max(a, max(b, max(c, max(d, e)))) bewerten. (Ich habe 4.2.1 auf gcc getestet.)

Beachten Sie, dass es wichtig ist, dass der Basisfall (MAX_OF_2) nicht wiederholt seine Argumente mehr als einmal in der Entwicklung (weshalb ich max in diesem Beispiel setzen). Andernfalls würden Sie die Länge der Erweiterung für jedes Niveau zu verdoppeln, so kann man sich vorstellen, was mit 64 Argumenten geschehen:)

Sie können diesen Betrug betrachten, da es nicht rekursiv ist und es ist die Arbeit in dem Prä-Prozessor nicht. Und es nutzt eine GCC-Erweiterung. Und es funktioniert nur für einen Typ. Es ist jedoch ein variadische MAX_OF_N Makro:

#include <iostream>
#include <algorithm>

#define MAX_OF_N(...) ({\
        int ra[] = { __VA_ARGS__ }; \
        *std::max_element(&ra[0], &ra[sizeof(ra)/sizeof(int)]); \
    })

int main() {
    int i = 12;
    std::cout << MAX_OF_N(1,3,i,6);
}

Ach ja, und wegen des möglichen variablen Ausdrucks in der Initialisierungsliste, glaube ich nicht, dass ein Äquivalent dieses (seine eigene Funktion mit std zu vermeiden :: max_element) in C89 funktionieren würde. Aber ich bin nicht sicher, variadische Makros ist entweder in C89.

Hier ist etwas, das ich denke, wird um die „nur eine Art“ Beschränkung. Es ist schon ein bisschen haarig, aber:

#include <iostream>
#include <algorithm>

#define MAX_OF_N(x, ...) ({\
        typeof(x) ra[] = { (x), __VA_ARGS__ }; \
        *std::max_element(&ra[0], &ra[sizeof(ra)/sizeof(ra[0])]); \
    })

int main() {
    int i = 12;
    std::cout << MAX_OF_N(i+1,1,3,6,i);
}

Ich denke, dass, auch wenn Sie rekursiv Makros erweitern könnte, da in Bezug auf die Effizienz ein kleines Problem mit dem Ansatz wäre ... wenn die Makros erweitert werden, wenn die MAX_OF_[N-1] größer ist, dann müssen Sie es erneut bewerten von Grund auf neu.

Dies ist eine dumme und dumme Antwort, dass wahrscheinlich niemand xD wie

Datei "source.c"

#include "my_macros.h"
...

Datei "Makefile"

myprogram: source.c my_macros.h
 gcc source.c -o myprogram

my_macros.h: make_macros.py
 python make_macros.py > my_macros.h

Datei "make_macros.py"

def split(l):
    n = len(l)
    return l[:n/2], l[n/2:]

def gen_param_seq(n):
    return [chr(i + ord("A")) for i in range(n)]

def make_max(a, b):
    if len(a) == 1:
        parta = "("+a[0]+")"
    else:
        parta = make_max(*split(a))

    if len(b) == 1:
        partb = "("+b[0]+")"
    else:
        partb = make_max(*split(b))

    return "("+parta +">"+partb+"?"+parta+":"+partb+")"

for i in range(2, 9):
    p = gen_param_seq(i)
    print "#define MAX_"+str(i)+"("+", ".join(p)+") "+make_max(*split(p))

dann haben Sie die hübschen Makros definiert:

#define MAX_2(A, B) ((A)>(B)?(A):(B))
#define MAX_3(A, B, C) ((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))
#define MAX_4(A, B, C, D) (((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D)))
#define MAX_5(A, B, C, D, E) (((A)>(B)?(A):(B))>((C)>((D)>(E)?(D):(E))?(C):((D)>(E)?(D):(E)))?((A)>(B)?(A):(B)):((C)>((D)>(E)?(D):(E))?(C):((D)>(E)?(D):(E))))
#define MAX_6(A, B, C, D, E, F) (((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))>((D)>((E)>(F)?(E):(F))?(D):((E)>(F)?(E):(F)))?((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C))):((D)>((E)>(F)?(E):(F))?(D):((E)>(F)?(E):(F))))
#define MAX_7(A, B, C, D, E, F, G) (((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))>(((D)>(E)?(D):(E))>((F)>(G)?(F):(G))?((D)>(E)?(D):(E)):((F)>(G)?(F):(G)))?((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C))):(((D)>(E)?(D):(E))>((F)>(G)?(F):(G))?((D)>(E)?(D):(E)):((F)>(G)?(F):(G))))
#define MAX_8(A, B, C, D, E, F, G, H) ((((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D)))>(((E)>(F)?(E):(F))>((G)>(H)?(G):(H))?((E)>(F)?(E):(F)):((G)>(H)?(G):(H)))?(((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D))):(((E)>(F)?(E):(F))>((G)>(H)?(G):(H))?((E)>(F)?(E):(F)):((G)>(H)?(G):(H))))

und das Beste daran ist, dass ... es funktioniert ^ _ ^

Wenn Sie diese Straße in C ++ going down sind, werfen Sie einen Blick auf Metaprogrammierung . Es ist nicht schön, und es kann Ihr genaues Problem nicht lösen, aber es wird Rekursion behandeln.

Zuerst Makros erweitern keine recusrsively. Obwohl, können Makros erneuten Eintritt durch ein Makro für jede Rekursion Ebene zu schaffen und dann die Rekursionstiefe herzuleiten. Doch all diese Wiederholung und herzuleiten Rekursion wird betreut von der

scroll top