I'm trying to reconcile the rules I find for creating variadic functions in C. On the one hand I see explicitly stated (for example, here) statements like "just before the ellipses is always an int". On the other hand, I see lots of example programs, including on stackoverflow that make no mention of such a rule (or convention), and in fact work without it. And I see many of the other form (the extra int), that also seem to work. (The most common function, in fact seems to be one defined like: int myFunc(char *format, ...)
and is used with sprintf
or friends).
I'm trying to wrap my head around how it works so that future efforts are based upon understanding, rather than based on the use of copy/paste. At present, for me, it might as well be a magic wand. So in order to understand how to get the most out of the option, I need to understand the rules. Can you help me understand why I find such conflicting requirements and why both conventions seem to work?
Thanks.
CodePudding user response:
The main rule regarding a variadic function is that you need some way of determining how many arguments you have and what the type of those arguments are, though not necessarily the way the tutorial say.
Generally, there are two ways: either one of the fixed arguments tells you the number and possibly the type of the variadic arguments, or one of the variadic arguments is a sentinel value which specifies the end of the argument list.
Examples from the standard library and POSIX:
printf
and family: The first argument is a format string, and the contents of this format string specify the number and type of each variadic argument.execl
: The second of its two fixed arguments is the first argument of an external program to run. If it is not NULL, variadic arguments are read as typeconst char *
until it finds one that is NULL.
A variation of the first option is as you mentioned: one of the fixed arguments is the number of variadic arguments, where each variadic argument has the same predetermined type. This is the simplest to implement, which is probably why the tutorial you linked suggested it.
Which of these you choose depends entirely on your use case.
Another interesting variation is the open
function on Linux and similar systems. The man pages show the following signatures:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
The actual declaration looks something like this:
extern int open (const char *__file, int __oflag, ...) __nonnull ((1));
In this case, one variadic argument is read if the flags
parameter includes the value O_CREAT
.
CodePudding user response:
There is no rule in the C standard that the parameter just before ...
in a function declaration must be an int
. The article you link to is merely referring to its particular example: When a function is declared with (int foo, ...)
, then the first argument passed to that specific function (after conversion from whatever the actual argument is; e.g., a char
argument will be converted to int
) is always an int
.
In general, you can have any types for the parameters before ...
. The only rule is there must be at least one explicit parameter before the ...
.