In a function with variable arguments, we initialize an object of type va_list ,'ap' with the function va_start() as:
void va_start(va_list ap, parmN);
I don't understand
1.what type of objects can be passed as parMN(last known parameter). I've done with examples of passing integers, strings with format specifiers, structures etc.
2. How the parMN describes the following optional parameters.
The C standard says that va_start() is actually a macro, not a function, so it can do things a function couldn't. The details are highly implementation dependent but you could imagine that it takes the address of parmN to determine the stack address of the next parameter. There's no need for va_start() to know about the types of the following parameters because that information is passed to va_arg(), which is another macro.
Related
I recently came across a strange syntax in C program.
struct connector_agent_api{
bool (*receive)(slot *s, uint8_t *data, uint8_t length);
}
Is "receive" a function pointer?
If it is a function pointer, why does it have named arguments? Should it be like the following one?
bool (*receive)(slot *, uint8_t *, uint8_t);
It certainly compiled and being used in a library. I searched on internet a lot and tried to justify this kind of syntax. I still don't know why this thing can be compiled... :(
The names of arguments in a function pointer are optional, just as the names of arguments in a function declaration are optional. This is because parameter names if given are not used, so both formats are allowed.
In section 6.7.6.3 of the C standard regarding Function Declarators, which includes both function prototypes and function pointers, paragraph 6 states:
A parameter type list specifies the types of, and may
declare identifiers for, the parameters of the function.
The only place where function parameters require a name is in the actual definition of a function.
For a function definition, Section 6.9.1p5 states:
If the declarator includes a parameter type list, the
declaration of each parameter shall include an identifier, except
for the special case of a parameter list consisting of a single
parameter of type void , in which case there shall not be an
identifier. No declaration list shall follow.
What makes you think it is a strange syntax? It is a valid declaration as per C standard. The fact that the parameters are named is irrelevant. The naming of such parameters is optional in this case. It can be really helpful if you or someone else is using an IDE because it could display the complete prototype upon using the function pointer to call the function and thus give a hint to the coder about the arguments to be supplied.
I was recently reading about the usage of const keyword as function arguments in C and the way to use that has been mentioned in When and for what purposes should the const keyword be used in C for variables and been accepted as correct answer. In this post, one point mentions that
Never use const in a function prototype for a parameter passed by
value. It has no meaning and is hence just 'noise'.
I used this way and it works for me but I am not sure why that is a noise for parameters passed by value and yet not a noise for the parameters passed by reference (more aptly the pointer values in C as there is not concept of pass by value and pass by reference in C). So, by this explanation when I pass a pointer as a function argument and use a const keyword; I have to do this for both the declaration in the header file and the definition in the C file but I need not use the const keyword for a non-pointer argument in the declaration (header file) and only use it while defining the function in the C file.
Any explanations?
The statement you quote is a bit misleading, because in C, all arguments are passed by value.* I suppose it is trying to distinguish between the arguments themselves and, for the special case of arguments that are pointers, their referents.
In any event, the point is that const-qualifying a function parameter in the function declaration conveys no information whatever to callers. Regardless of such qualification, the function cannot modify the caller's copy of any argument anyway, because arguments are passed by value.
*Note, however, that arrays are never passed at all. In function call expressions, as in most contexts, array values "decay" to pointers, and those pointers are passed by value. This produces an effect similar, but not identical, to what you would have if arrays were passed by reference.
It's the rule. If in the declaration of a function, you don't mark your parameters const, you can mark them const in the definition.
Some folk like to mark as many parameters const as possible in the definition since it can guard against unintentional modification of the function parameters; which could introduce bugs. Personally I don't do this but plenty of houses (including a large bank headquartered in Scotland) insist on the style.
Posting this here because I wrote it for a code review and figured it was worth preserving:
Adding const to a value-type parameter in the function declaration is useless. The caller won't care whether the parameter is modified or not because the caller's data won't be affected in any way. The parameter is a separate object than the argument that was passed in, constructed by copy [or by move for rvalue arguments into move-constructible parameters (since C++11)].
Adding const to a value-type parameter in the function definition marks the separate, function-local object as const. This is essentially the same as marking a local variable 'const', and value-type parameters should usually be treated as local variables when determining whether the value-type should be const.
The C & C++ standards demand that compilers & linkers be smart enough to match the following declaration with its definition:
// Declaration
void Foo(int bar);
// Definition
void Foo(const int bar){
printf("%i", bar);
}
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.
Here I found an example of how varargs can be used in C.
#include <stdarg.h>
double average(int count, ...)
{
va_list ap;
int j;
double tot = 0;
va_start(ap, count); //Requires the last fixed parameter (to get the address)
for(j=0; j<count; j++)
tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return tot/count;
}
I can understand this example only to some extent.
It is not clear to me why we use va_start(ap, count);. As far as I understand, in this way we set the iterator to its first element. But why it is not set to the beginning by default?
It is not clear to me why we need to give count as an argument. Can't C automatically determine the number of the arguments?
It is not clear to me why we use va_end(ap). What does it change? Does it set the iterator to the end of the list? But is it not set to the end of the list by the loop? Moreover, why do we need it? We do not use ap anymore; why do we want to change it?
Remember that arguments are passed on the stack. The va_start function contains the "magic" code to initialize the va_list with the correct stack pointer. It must be passed the last named argument in the function declaration or it will not work.
What va_arg does is use this saved stack pointer, and extract the correct amount of bytes for the type provided, and then modify ap so it points to the next argument on the stack.
In reality these functions (va_start, va_arg and va_end) are not actually functions, but implemented as preprocessor macros. The actual implementation also depends on the compiler, as different compilers can have different layout of the stack and how it pushes arguments on the stack.
But why it is not set to the beginning by default?
Maybe because of historical reasons from when compilers weren't smart enough. Maybe because you might have a varargs function prototype which doesn't actually care about the varargs and setting up varargs happens to be expensive on that particular system. Maybe because of more complex operations where you do va_copy or maybe you want to restart working with the arguments multiple times and call va_start multiple times.
The short version is: because the language standard says so.
Second, it is not clear to me why we need to give count as an argument. Can't C++ automatically determine the number of the arguments?
That's not what all that count is. It is the last named argument to the function. va_start needs it to figure out where the varargs are. Most likely this is for historical reasons on old compilers. I can't see why it couldn't be implemented differently today.
As the second part of your question: no, the compiler doesn't know how many arguments were sent to the function. It might not even be in the same compilation unit or even the same program and the compiler doesn't know how the function will be called. Imagine a library with a varargs function like printf. When you compile your libc the compiler doesn't know when and how programs will call printf. On most ABIs (ABI is the conventions for how functions are called, how arguments are passed, etc) there is no way to find out how many arguments a function call got. It's wasteful to include that information in a function call and it's almost never needed. So you need to have a way to tell the varargs function how many arguments it got. Accessing va_arg beyond the number of arguments that were actually passed is undefined behavior.
Then it is not clear to me why do we use va_end(ap). What does it change?
On most architectures va_end doesn't do anything relevant. But there are some architectures with complex argument passing semantics and va_start could even potentially malloc memory then you'd need va_end to free that memory.
The short version here is also: because the language standard says so.
va_start initalises the list of variable arguments. You always pass the last named function argument as the second parameter. It is because you need to provide information about location in the stack, where variable arguments begin, since arguments are pushed on the stack and compiler cannot know where there's a beginning of variable argument list (there's no differentiation).
As to va_end, it is used to free resources allocated for the variable argument list during the va_start call.
It's C macroses. va_start sets internal pointer to address of first element. va_end cleanup va_list. If there is va_start in code and there is no va_end - it's UB.
The restrictions that ISO C places on the second parameter to the va_start() macro in header
are different in this International Standard. The parameter parmN is the identifier of the rightmost parameter
in the variable parameter list of the function definition (the one just before the ...). If the parameter
parmN is declared with a function, array, or reference type, or with a type that is not compatible with the
type that results when passing an argument for which there is no parameter, the behavior is undefined.
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?