According to what is written in the explanation in C - Variable Arguments:
Define a function with its last parameter as ellipses and the one just before the ellipses is always an int which will represent the number of arguments.
Is it really a must to send an int to the ellipse function before ...?
I saw the prototype of the printf() function, and before ... the function gets const char * and there isn't any int before the ....
No, passing an int is not a REQUIREMENT, as proved by printf(). What you see in the tutorial is specific to the func() and average() examples presented by the tutorial (although the func() example does not match the int explanation correctly, but the average() example does).
Only the caller knows how many parameter values it is passing in (and of what type(s)), so you need to design your variadic functions in such a way that the caller has to specify how many parameter values are actually being passed in (and optionally their types). There are two ways to do that:
passing in a required leading parameter. This could be an int specifying the exact argument count. Or it could be a string that the function parses to determine the arguments (this is what printf does).
passing in a required sentry value as the last argument value. Then the function simply uses all of the arguments it finds until it reaches that sentry.
Related
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.
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 type const 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.
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 ....
I am reading http://www.cs.utexas.edu/users/lavender/courses/cs345/lectures/CS345-Lecture-07.pdf to try to understand how does Stack Activation Frame for Variable arguments functions works?
Specifically how can the called function knows how many arguments are being passed?
The slide said:
The va_start procedure computes the fp+offset value following the argument
past the last known argument (e.g., const char format). The rest of the arguments are then computed by calling
va_arg, where the ‘ap’ argument to va_arg is some fp+offset value.*
My question is what is fp (frame point)? how does va_start computes the 'fp+offset' values?
and how does va_arg get 'some fp+offset values? and what does va_end supposed to do with stack?
The function doesn't know how many arguments are passed. At least not in any way that matters, i.e. in C you cannot query for the number of arguments.
That's why all varargs functions must either:
Use a non-varying argument that contains information about the number and types of all variable arguments, like printf() does; or
Use a sentinel value on the end of the variable argument list. I'm not aware of a function in the standard library that does this, but see for instance GTK+'s gtk_list_store_set() function.
Both mechanisms are risky; if your printf() format string doesn't match the arguments, you're going to get undefined behavior. If there was a way for printf() to know the number of passed arguments, it would of course protect against this, but there isn't. So it can't.
The va_start() macro takes as an argument the last non-varying argument, so it can somehow (this is compiler internals, there's no single correct or standard answer, all we can do from this side of the interface is reason from the available data) use that to know where the first varying argument is located on the stack.
The va_arg() macro gets the type as an "argument", which makes it possible to use that to compute the offset, and probably increment some state in the va_list object to point at the next varying argument.
I am currently changing the function signatures of a class of functions in an application. These functions are being stored in a function table, so I was expecting to change this function table as well. I have just realised that in certain instances, we already use the new function signature. But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
When the function is called, it will be passed extra parameters that are not really part of the function declaration, but they are on the end of the parameter list.
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
It evidently works just fine across multiple platforms but out of curiosity I'd like to know how and why it works.
But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
So the compiler gets to be no help to speak of. C programmers cast too much. >_<
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
Technically, you've got undefined behavior. But it's defined for your platform to use the standard C calling conventions (see Scott's answer), or something that maps directly to them (usually by mapping the first N parameters to a certain set of processor registers).
This comes up a lot with variable argument lists, too. For example, printf is declared something like:
int printf(const char* format, ...);
And its definition usually uses the stdarg system to handle the extra arguments, which looks like:
#include <stdarg.h>
int printf(const char* format, ...)
{
va_list ap;
int result;
va_start(ap, format);
result = vprintf(format, ap);
va_end(ap);
return result;
}
If you're on a platform with standard C calling conventions, that va_end(ap) macro usually turns into a do-nothing. In this case, you can get away with passing extra arguments to a function. But on some platforms, the va_end() call is required to restore the stack to a predictable state (i.e. where it was before the call to va_start); in those cases, your functions will not leave the stack the way it found it (it won't pop enough arguments back off the stack) so your calling function could, for example, crash on exit when it fetches a bogus value for a return address.
Your functions must certainly be using the cdecl calling convention (http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl). This pushes arguments on the stack in reverse order, from right to left, ensuring that the last argument can be easily located (top of the stack) and used to interpret the remainder, such as a printf format string. It is also the responsibility of the caller to clean up the stack, which is a bit less compact than the function itself doing so (as in pascal/stdcall convention), but ensures that variable argument lists can be used, and implies that trailing arguments can be ignored.
I know the reasons why this is a bad idea and I also know that this is the reason C++ templates were created, but I'm doing it in C for the fun and learning.
I'm embedding Python into my application and I wanted to make it possible to register certain C functions, with any arbitrary type, to be callable at the application run-time. Because of this a pointer to them is stored (as a simple void*).
With some basic macro fun I have gotten all the information I need about these functions and stored that too - the function pointer, the size of the return value (and if it is void), the number of arguments and each of their sizes.
So I'm stuck at the final stage - which is the actual calling of the function pointer with the appropriate data. I'm fairly certain this sort of thing should be possible (I've caused stack errors in my own time), but I was wondering if there was a more...legitimate way to do it.
I guess the ideal would look something like this:
void call_function(void* function, void* return, void* arg_data, int arg_data_size);
Does such a thing exists?
Thanks
You can declare a function pointer void* (*f) (void*); that points to a function that takes a void* argument and returns a void* return value -- you can put this in the first parameter of call_function.
Then call call_function as:
void* function(void*);
ret_type ret;
arg_type arg_data;
call_function(&function, (void*)&ret, (void*)&arg_data, sizeof(arg_data));
where arg_type is the actual argument type you want to use inside function and ret_type is the actual type of the return value of function.
Note: you might want to specify the size of the return value type as well.
Note: this will work with any function of one argument. The solution can be extended to a fixed/known number of arguments in function, but not to handle an unknown number of arguments.
Note: naming the second parameter return is not allowed as return is a keyword.
I'm trying to plug a hole in my knowledge. Why variadic functions require at least two arguments? Mostly from C's main function having argc as argument count and then argv as array of arrays of chars? Also Objective-C's Cocoa has NSString methods that require format as first argument and afterwards an array of arguments ([NSString stringWithFormat:#"%#", foo]). Why is it impossible to create a variadic function accepting only a list of arguments?
argc/argv stuff is not really variadic.
Variadic functions (such as printf()) use arguments put on the stack, and don't require at least 2 arguments, but 1.
You have void foo(char const * fmt, ...) and usually fmt gives a clue about the number of arguments.
That's minimum 1 argument (fmt).
C has very limited reflection abilities so you must have some way to indicate what it is that the variable arguments contain - either specifying the number of arguments or the type of them (or both), and that is the logic behind having one more parameter. It is required by the ISO C standard so you can't omit it. If feel you don't need any extra parameters because the number and type of the arguments is always constant then there is no need for variable arguments in the first place.
You could of course design other ways to encode the number / type information inside the variable arguments such as a sentinel value. If you want to do this, you can just supply a dummy value for the first argument and not use it in the method body.
And just to be pedantic about your title, variadic functions only require one argument (not two). It's perfectly valid to make a call to a variadic function without providing any optional arguments:
printf("Hello world");
I think, that the reason is the following:
in the macro va_start(list, param); you specify the last fixed argument - it is needed to determine the address of the beginning of the variable arguments list on the stack.
How would you then know if the user provided any arguments?
There has to be some information to indicate this, and C in general wasn't designed to do behind-your-back data manipulation. So anything you need, it makes you pass explicitly.
I'm sure if you really wanted to you could try to enforce some scheme whereby the variadic function takes only a certain type of parameter (a list of ints for example) - and then you fill some global variable indicating how many ints you had passed.
Your two examples are not variadic functions. They are functions with two arguments, but they also highlight a similar issue. How can you know the size of a C array without additional information? You can either pass the size of the array, or you describe a scheme with some sentinel value demarcating the end of the array (i.e. '\0' for a C string).
In both the variadic case and the array case you have the same problem, how can you know how much data you have legitimate access to? If you don't know this with the array case, you will go out of bounds. If you don't know this with the variadic case you will call va_arg too many times, or with the wrong type.
To turn the question around, how would you be able to implement a function taking a variable number of arguments without passing the extra information?