YAKOVM
YAKOVM

Reputation: 10153

Variable numbers of arguments

I have several questions regarding variable numbers of arguments:

  1. Why are va_start, va_arg, and va_end defined as macros and not as functions?

  2. 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

Answers (3)

Shafik Yaghmour
Shafik Yaghmour

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)(&param + 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

Jay
Jay

Reputation: 202

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). Actually 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

Jerry Coffin
Jerry Coffin

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

Related Questions