Reputation: 451
if I had a function receiving variable length argument
void print_arg_addr (int n, ...)
I can use these three macro to parse the argument
va_start(ap,v)
va_arg(ap,t)
va_end(ap)
In my understanding,
va_start lets ap point to second parameter,
va_arg move ap to next parameter,
va_end lets ap point to NULL.
so I use the snippet below to check my understanding, but it turns out that ap does not change, I expect ap will increment by 4 each time.
void print_arg_addr (int n, ...)
{
int i;
int val;
va_list vl;
va_start(vl,n);
for (i=0;i<n;i++)
{
val=va_arg(vl,int);
printf ("ap:%p , %d\n",vl,val);
}
va_end(vl);
printf ("ap:%p \n",vl);
}
int main()
{
print_arg_addr(5,1,2,3,4,5);
}
output:
ap:0x7ffc62fb9890 , 1
ap:0x7ffc62fb9890 , 2
ap:0x7ffc62fb9890 , 3
ap:0x7ffc62fb9890 , 4
ap:0x7ffc62fb9890 , 5
ap:0x7ffc62fb9890
Thank you!
Upvotes: 2
Views: 640
Reputation: 1
A va_list
(like your vl
) is some abstract data type that you are not allowed to pass to printf
. Its implementation is private to your compiler (and processor architecture), and related to the ABI and calling conventions. Compile your code with all warnings and debug info: gcc -Wall -Wextra -g
. You'll get warnings, and you have undefined behavior so you should be very scared.
In other words, consider va_list
, va_start
, va_end
(and all stdarg(3) ...) as some magic provided by the compiler. That is why they are part of the C11 specification (read n1570) and often implemented as compiler builtins.
If you need to understand the internals of va_list
and friends (but you should not need that), dive inside your compiler (and study your ABI). Since GCC is free software of millions of source code lines, you could spend many years studying it. In your case, I don't think it is worth the effort.
You might also look at the generated assembler code (a .s
file), using gcc -O -S -fverbose-asm
Current calling conventions use processor registers. This is why understanding the details of variadic calls is complex. In the 1980s, arguments were pushed on the machine stack, and at that time va_start
returned some pointer into the stack. Things are much more complex now, and you don't want to dive into that complexity.
Upvotes: 3