Reputation: 10153
I have several questions regarding variable numbers of arguments:
Why are va_start
, va_arg
, and va_end
defined as macros and not as functions?
How does va_start
work? Does it have an access to the function call stack and it traverses the stack until it finds last specified argument?
Upvotes: 4
Views: 191
Reputation: 158449
The rationale for why they are macros is covered in the Rationale for International Standard—Programming Languages—C in section 7.15
Variable arguments it says:
va_start and va_arg must exist as macros, since va_start uses an argument that is passed by name and va_arg uses an argument which is the name of a data type.
This article How Variable Argument Lists Work in C covers why in more detail and gives a possible x86 implementation:
typedef char *va_list;
#define va_start( list, param ) (list = (va_list)(¶m + sizeof( param )))
#define va_arg( list, type ) (*(type *)((list += sizeof( type )) - sizeof( type ))
In C++ you have a lot of other alternatives and Variable number of arguments in C++? probably covers all of them.
Upvotes: 2
Reputation: 202
Actually va_end
doesn't need to be implemented as a macro, and neither, I think, does va_start (you'd just have to add &
to the parameters to pass a pointer to them).va_end
and va_start
have to be imlemented as macros because you can't use &
in all cases, as was pointed out in the comments.
va_arg
must be implemented as a macro because you need to provide a type as a parameter to it, which you can't do without macros.
va_start
works as you presume: you give it the first argument, and it can calculate based on the size of that argument what position the other arguments are at, because they are all contiguous on the stack.
It simply starts the va_list
pointing at the end of the first argument (which you pass to va_start
) and adds the size of the next one every time you use va_arg
.
Upvotes: 1
Reputation: 490018
va_start
, va_arg
and va_end
normally have to execute in the context of the variadic function to do their jobs, so making them functions would make them either a lot more complex, or (in some cases) outright impossible to implement.
The details of how it works are left to the implementation. In a typical case, arguments to variadic functions will be pushed left to right, so the first argument will be closest to the top of the stack. To get to it, va_arg
only needs to know the basic structure of a stack frame, such as how large the return address is (the top argument will typically be right next to it).
Upvotes: 0