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.