How are variable arguments implemented in gcc?

int max(int n, ...) 

I use the cdecl calling cdecl when the caller clears the variable after the caller returns.

I am interested to know how the macros va_end , va_start and va_arg ?

Does the caller pass in the address of the array of arguments as the second argument max?

+17
c gcc
Sep 11
source share
3 answers

If you look at how the C language stores parameters on the stack, the way macros work should be clear: -

 Higher memory address Last parameter Penultimate parameter .... Second parameter Lower memory address First parameter StackPointer -> Return address 

(note that depending on the hardware, the stack pointer may contain one line down, and the top and bottom can be replaced)

Arguments are always stored as 1 even without the parameter type ...

The va_start macro simply sets the pointer to the first parameter of the function, for example: -

  void func (int a, ...) { // va_start char *p = (char *) &a + sizeof a; } 

which indicates that p points to the second parameter. The va_arg macro does the following: -

  void func (int a, ...) { // va_start char *p = (char *) &a + sizeof a; // va_arg int i1 = *((int *)p); p += sizeof (int); // va_arg int i2 = *((int *)p); p += sizeof (int); // va_arg long i2 = *((long *)p); p += sizeof (long); } 

The va_end macro simply sets p to NULL .

NOTES:

  • Optimization of compilers and some RISC processors stores parameters in registers rather than using the stack. Having a parameter ... will disable this ability and use the stack for the compiler.
+22
Sep 11
source share

As arguments are passed on the stack, the va_ functions (which are implemented most of the time as macros) simply manipulate the private stack pointer. This private stack pointer is stored from the argument passed to va_start , and then va_arg "issues" the arguments from the "stack" when it iterates over the parameters.

Suppose you call the max function with three parameters, for example:

 max(a, b, c); 

Inside the max function, the stack basically looks like this:

       + ----- +
       |  c |
       |  b |
       |  a |
       |  ret |
 SP -> + ----- +

SP is a real pointer to the stack, and it’s not really a , b and c that are on the stack, but their values. ret is the return address where to go to the function.

That va_start(ap, n) does takes the address of the argument ( n in the function prototype), and the position of the next argument is calculated from it, so we get a new pointer to the private stack:

       + ----- +
       |  c |
 ap -> |  b |
       |  a |
       |  ret |
 SP -> + ----- +

When you use va_arg(ap, int) , it returns what the private stack pointer points to, and then pops it up, changing the private stack pointer to now point to the next argument. The stack now looks like this:

       + ----- +
 ap -> |  c |
       |  b |
       |  a |
       |  ret |
 SP -> + ----- +

This description, of course, is simplified, but shows the principle.

+8
Sep 11 '12 at 14:13
source share
 int max(int n, const char *msg,...) { va_list args; char buffer[1024]; va_start(args, msg); nb_char_written = vsnprintf(buffer, 1024, msg, args); va_end(args); printf("(%d):%s\n",n,buffer); } 
0
Sep 11 '12 at 14:25
source share



All Articles