Es ist machbar – der Mechanismus wurde in der Newsgroup comp.std.c im Januar 2006 erklärt. Dazu gab es kürzlich eine weitere Frage in SO 2124339.
Ich habe den Code versteckt, nur für den Fall…
#ifndef JLSS_ID_NARG_H
#define JLSS_ID_NARG_H
/*
** http://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1
**
** Newsgroups: comp.std.c
** From: Laurent Deniau <[email protected]>
** Date: Mon, 16 Jan 2006 18:43:40 +0100
** Subject: __VA_NARG__
**
** A year ago, I was asking here for an equivalent of __VA_NARG__ which
** would return the number of arguments contained in __VA_ARGS__ before its
** expansion. In fact my problem at that time (detecting for a third
** argument) was solved by the solution of P. Mensonides. But I was still
** thinking that the standard should have provided such a facilities rather
** easy to compute for cpp.
**
** This morning I had to face again the same problem, that is knowing the
** number of arguments contained in __VA_ARGS__ before its expansion (after
** its expansion can always be achieved if you can do it before). I found a
** simple non-iterative solution which may be of interest here as an answer
** to who will ask in the future for a kind of __VA_NARG__ in the standard
** and I post it for archiving. May be some more elegant-efficient solution
** exists?
**
** Returns NARG, the number of arguments contained in __VA_ARGS__ before
** expansion as far as NARG is >0 and <64 (cpp limits):
**
** #define PP_NARG( ...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
** #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
** #define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,[..],_61,_62,_63,N,...) N
** #define PP_RSEQ_N() 63,62,61,60,[..],9,8,7,6,5,4,3,2,1,0
**
** [..] stands for the continuation of the sequence omitted here for
** lisibility.
**
** PP_NARG(A) -> 1
** PP_NARG(A,B) -> 2
** PP_NARG(A,B,C) -> 3
** PP_NARG(A,B,C,D) -> 4
** PP_NARG(A,B,C,D,E) -> 5
** PP_NARG(A1,A2,[..],A62,A63) -> 63
**
** ======
**
** Newsgroups: comp.std.c
** From: Roland Illig <[email protected]>
** Date: Fri, 20 Jan 2006 12:58:41 +0100
** Subject: Re: __VA_NARG__
**
** Laurent Deniau wrote:
** > This morning I had to face again the same problem, that is knowing the
** > number of arguments contained in __VA_ARGS__ before its expansion (after
** > its expansion can always be achieved if you can do it before). I found a
** > simple non-iterative solution which may be of interest here as an answer
** > to who will ask in the future for a kind of __VA_NARG__ in the standard
** > and I post it for archiving. May be some more elegant-efficient solution
** > exists?
**
** Thanks for this idea. I really like it.
**
** For those that only want to copy and paste it, here is the expanded version:
**
** // Some test cases
** PP_NARG(A) -> 1
** PP_NARG(A,B) -> 2
** PP_NARG(A,B,C) -> 3
** PP_NARG(A,B,C,D) -> 4
** PP_NARG(A,B,C,D,E) -> 5
** PP_NARG(1,2,3,4,5,6,7,8,9,0, // 1..10
** 1,2,3,4,5,6,7,8,9,0, // 11..20
** 1,2,3,4,5,6,7,8,9,0, // 21..30
** 1,2,3,4,5,6,7,8,9,0, // 31..40
** 1,2,3,4,5,6,7,8,9,0, // 41..50
** 1,2,3,4,5,6,7,8,9,0, // 51..60
** 1,2,3) -> 63
**
**Note: using PP_NARG() without arguments would violate 6.10.3p4 of ISO C99.
*/
/* The PP_NARG macro returns the number of arguments that have been
** passed to it.
*/
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63, N, ...) N
#define PP_RSEQ_N() \
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
#endif /* JLSS_ID_NARG_H */
Es funktioniert gut, solange es nicht mehr als 64 Argumente gibt. Hier ist der Testcode, den ich verwendet habe:
#include "narg.h"
#include <stdio.h>
#define PRINT(pp_narg) printf("%2d = %s\n", pp_narg, # pp_narg)
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_narg_c[];
const char jlss_id_narg_c[] = "@(#)$Id: narg.c,v 1.2 2010/01/24 18:12:05 jleffler Exp $";
#endif /* lint */
int
main(void)
{
PRINT(PP_NARG(A));
PRINT(PP_NARG(A, B));
PRINT(PP_NARG(A, B, C));
PRINT(PP_NARG(A, B, C, D));
PRINT(PP_NARG(A, B, C, D, E));
PRINT(PP_NARG(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 1..10
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 11..20
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 21..30
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 31..40
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 41..50
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 51..60
1, 2, 3));
/**
** If the number of arguments to PP_NARG() is greater than 63, the
** 64th argument is returned. This is well-defined behaviour, but
** not exactly what was intended.
*/
PRINT(PP_NARG(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 1..10
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 11..20
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 21..30
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 31..40
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 41..50
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 51..60
1, 2, 3, -123456789));
PRINT(PP_NARG(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 1..10
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 11..20
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 21..30
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 31..40
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 41..50
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, // 51..60
1, 2, 3, -123456789, -987654321));
return(0);
}
Mir ist klar, dass dies eine ziemlich alte Frage ist, aber da noch nie jemand auf den „Bonus“ geantwortet hat, um die Zahl zu den Funktionsnamen hinzuzufügen, ist hier ein Beispiel für diesen Teil, bei dem Jonathans Antwort der Kürze halber auf 9 Argumente reduziert ist. Es geht davon aus, dass Sie die nummerierten Funktionen vordefiniert haben oder diese als Grundlage verwenden, um sie zu definieren.
#define MKFN(fn,...) MKFN_N(fn,##__VA_ARGS__,9,8,7,6,5,4,3,2,1,0)(__VA_ARGS__)
#define MKFN_N(fn,n0,n1,n2,n3,n4,n5,n6,n7,n8,n,...) fn##n
#define myfunc(...) MKFN(myfunc,##__VA_ARGS__)
myfunc();
myfunc(a,b,c,d,e,f);
//gcc -E this.c
//myfunc0();
//myfunc6(a,b,c,d,e,f);
Ein Ort, an dem ich diese Art von Funktionen gesehen habe, war in den Syscalls des Linux-Kernels, aber die Zahlen waren um eins falsch, weil das erste Argument die Syscall-Nummer ist (normalerweise als __NR_irgendwas definiert), also ist hier ein Beispiel, das dies berücksichtigt.
#define MKFN(fn,...) MKFN_N(fn,##__VA_ARGS__,9,8,7,6,5,4,3,2,1,0)(__VA_ARGS__)
#define MKFN_N(fn,NR,n0,n1,n2,n3,n4,n5,n6,n7,n8,n,...) fn##n
#define syscall(...) MKFN(syscall,##__VA_ARGS__)
syscall(__NR_fork);
syscall(77,a,b,c,d,e,f);//fake example
Warum nicht einfach eine Funktion mit einer Argumentliste variabler Länge verwenden?
– Anonym.
22. Februar 2010 um 1:14 Uhr
Wenn Sie es auf sinnvolle Weise tun könnten, würden wir es jetzt alle tun, und Sie wüssten es.
– Benutzer14554
22. Februar 2010 um 1:14 Uhr
@jbcreix Mit diesem Ansatz können Sie nichts Neues erfinden 🙂 Es ist möglich – siehe meine Antwort unten.
– qrdl
22. Februar 2010 um 6:17 Uhr
@Anon, in C in einer Argumentliste mit variabler Länge müssen Sie die Anzahl der Argumente auf die eine oder andere Weise kennen. ZB kann printf abstürzen, wenn Ihre Anzahl an Argumenten nicht der im Formatstring erwarteten Anzahl entspricht (eigentlich: nur wenn nicht genügend Argumente angegeben werden und dann kommt es auch noch auf die Typen an).
– Patrick
22. Februar 2010 um 6:26 Uhr