Das zweite Makro ist sicherer, sondern verwendet eine Nicht-Standard-C-Erweiterung von GCC zur Verfügung gestellt passieren würde: statement expressions. Aber der erste Ausdruck ist "generisch". Mit der typeof Erweiterung des GCC helfen würde:
#define mymax(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); \
_a > _b ? _a : _b; })
zu kämpfen gegen die Ausgabe in JaredPar's answer angehoben Sie Präprozessor concatenation und GCC spezifischen __COUNTER__
(oder nur der mehr Standard __LINE__
) verwenden könnten, z.B.
#define mymax_counted(a,b,c) ({typeof(a) _a##c = (a); \
typeof(b) _b##c = (b); \
_a##c > _b##c ? _a##c : _b##c; })
#define mymax(a,b) mymax_counted(a,b,__COUNTER__)
aber auch das nicht ganz ausfallsicher ist (mit Pech, in einem gewissen Aufruf wie mymax(_a123,_b123)
kollidieren könnte, wenn die einzigartigen __COUNTER__
zu diesem Zeitpunkt seine 123 passiert).
Eigentlich mit einem inline function besser ist (denn wenn man mymaxfun(i++,t[i])
das Verhalten nennen ist gut definiert und gibt das gleiche Ergebnis wie mymaxfun(t[i],i++)
, und weil optimierende Compiler würde Code so effizient wie erzeugen, wenn sie mit einem Makro):
static inline int mymaxfun(int a, int b) { return (a>b)?a:b; }
Leider, C haben keine generischen Funktionen (in Betracht ziehen, für die Umstellung auf C++ mit seiner templates und std::max verwenden); jedoch C11 hat typgenerische Ausdrücke mit dem _Generic
Stichwort
Makros nützlich sind (wenn gemeistert), aber Sie sollten sehr vorsichtig sein, über Nebenwirkungen in Argumente, wenn Makros Aufruf (zB mymax(i++,t[--i]++)
), so sollten Sie immer Pflege und Dokument wenn ein Name ein Makro oder etwas anderes ist (wie eine Funktion). Als Faustregel gilt es, Nebeneffekte zu vermeiden - namentlich ++
oder --
, aber auch viele andere - in funktionsaufrufenden Ausdrücken (sowohl Funktionsaufrufe als auch Makroaufrufe).
Schauen Sie sich die Präprozessor-erweiterte Form Ihres Quellcodes an; Führen Sie also für einen foo.c
-Quellcode gcc -C -E foo.c > foo.i
aus (fügen Sie alle Präprozessoroptionen hinzu, wie -I
, -D
usw.) und schauen Sie in das Verzeichnis foo.i
, z. mit less foo.i
; es ist immer lehrreich.
Denken Sie darüber nach, was vom Präprozessor mit 'max (++ i, --j)' erzeugt wird. Und * weder * ist "sicher", aber Letzteres ist nicht so anfällig für Nebenwirkungen im Zusammenhang mit Makro-Parameter-Erweiterung. – WhozCraig
Zweitens ist sicherer. z.B. rufe 'max (i ++, j ++) 'oder' max '(fn1(), fn2())' – anishsane
auf. Beachten Sie, dass das zweite dieser Makros eine 'gcc' Erweiterung verwendet (eine Block-Anweisung als Ausdruck behandelt) und ist daher nicht tragbar. – templatetypedef