Document directory
- [Prototype]
- [Description]
- [Usage]
- [Implementation Analysis]
- [Example]
[Prototype]
Type fun (type arg1, type arg2,...
);
[Description]
It is mainly used in functions with uncertain number of parameters, such as printf.
[Usage]
Reference: glib/manual/Add. c
# Include <stdarg. h> <br/> # include <stdio. h> <br/> int add_em_up (INT count ,...) <br/>{ <br/> va_list AP; <br/> int I, sum; <br/> va_start (AP, count);/* initialize the argument list. */<br/> sum = 0; <br/> for (I = 0; I <count; I ++) <br/> sum + = va_arg (AP, INT);/* Get the next argument value. */<br/> va_end (AP);/* clean up. */<br/> return sum; <br/>}< br/> int main (void) <br/>{< br/>/* This call prints 16. */<br/> printf ("% d/N", add_em_up (3, 5, 5, 6); <br/>/* This call prints 55. */<br/> printf ("% d/N", add_em_up (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); <br/> return 0; <br/>}
Running result:
16
55
[Implementation Analysis]
To implement variable parameters, the key isHow to traverse the function list
This involves the storage order of function parameter linked lists in the stack:
The function stack entry process is roughly as follows: (for more details, refer to here.
)
- Function Local variables are added to the stack;
- Other information pointers of the called functions are written into the stack;
- Function return address into stack;
- The parameter list is added to the stack in sequence from right to left;
In this case, we can clearly define the storage order of the parameter list, as shown below:
Therefore, we must know the top parameter address of the stack, that is, the first parameter of the function;
It mainly depends on three macros defined in stdarg. h:
- Void va_start (va_list arg_ptr, prev_param);/* address of the first parameter */
- Type va_arg (va_list arg_ptr, type);/* starts from the second parameter and returns */
- Void va_end (va_list arg_ptr);/* indicates that the mark has been completed. In fact, nothing is done */
The implementation and comments of stdarg. h are as follows:
# Ifndef _ stdarg_h <br/> # DEFINE _ stdarg_h <br/> typedef char * va_list; <br/>/* perform memory Alignment Based on the Type value */<br/> # DEFINE _ va_rounded_size (type)/<br/> (sizeof (type) + sizeof (INT)-1)/sizeof (INT) * sizeof (INT) </P> <p>/* According to the address of the first parameter lastarg, obtain the second parameter address */<br/> # define va_start (AP, lastarg) (AP = (char *) & (lastarg) + _ va_rounded_size (lastarg ))) <br/>/* completed, no need to do */<br/> # define va_end (AP) <br/>/* return the parameter value pointed to by the current AP Based on the type, AP points to the next <br/> here, the comma expression is used. The result is displayed on the left, right, and right. <Br/> aP + = _ va_rounded_size (type), pointing to the next parameter; <br/> (AP + = _ va_rounded_size (type), returning the previous parameter; <br/> */<br/> # define va_arg (AP, type)/<br/> (AP + = _ va_rounded_size (type), * (type *) (ap-_ va_rounded_size (type) <br/> # endif/* _ stdarg_h */
In fact, the implementation of stdarg. h varies depending on the compiler. For more information, see here.
.
[Example]
In this example, we can modify glib/manual/Add. C as follows: add_ex.c
# Include <stdarg. h> <br/> # include <stdio. h> <br/> int show_arg (INT count ,...) <br/>{< br/> va_list AP; <br/> int I = 1; <br/> va_start (AP, count ); /* specify the address of the first parameter */<br/> printf ("first Arg address = % d/N", (unsigned INT) AP-sizeof (count )); <br/> for (I = 1; I <= count; I ++) <br/> printf ("% d = % d/T next_addh = % d/N", I, va_arg (AP, INT), (unsigned INT) AP ); /* take the next parameter in a loop */<br/> va_end (AP);/* end */<br/> return 0; <br/>}< br/> int main (void) <br/>{</P> <p>/* We intentionally set one more Count value, <br/> the sixth value is the return address of the function */<br/> show_arg (10, 1, 2, 3, 4, 5 ); <br/> return 0; <br/>}< br/>
Running result: the GCC and VC compilation results are different.
Reprinted please declare to: http://blog.csdn.net/oncoding/archive/2009/09/13/4549160.aspx