They are created at compile time. Rather then passing a list of discrete parameters, you use the va_start macro to get a stack address wrapped in the returned va_list structure. The va_start macro uses the last defined argument passed to the function, so it is usual to use this to provide a mechanism to determine the actual, run time number of arguments as well as their types. For example, printf requires a format string as the other arguments may be different sizes, whereas the code below uses a simple count as it expects only integers.
int average(int count, ...)
{
va_list valist;
int total;
int i;
// Initialize valist for number of arguments specified by count.
va_start(valist, count);
// Get the total of the variable arguments in the va_list.
for(total = 0, i = 0; i < num; i++)
{
// Use va_arg to access the next element in the va_list
// by passing the list and the type of the next argument.
total += va_arg(valist, int);
}
// Release the va_list memory.
va_end(valist);
return total/count;
}
// Using the function: pass the number of arguments
// then the arguments themselves.
printf("The average is %d.", average(3, 1, 2, 3));
Output: The average is 2.
gcc -S. Arguments (vararg) are processed at run time though.