First, what are variable parameters?
Int printf (const char * format ,...);
You can see the definition of printf. There is only one fixed const char * parameter, followed by a list of parameters with an indefinite length.
Second, write a Variable Parameter Function.
1. The parameter method is similar to printf. The first parameter is a fixed parameter, which is replaced;
2. Include the stdarg. h header file, because several macros defined in them need to be used;
Void va_start (va_list arg_ptr, prev_param );
Type va_arg (va_list arg_ptr, type );
Void va_end (va_list arg_ptr );
Va indicates the Variable Argument variable parameter.
3. A va_list type variable is defined in the function. It is a pointer storing the parameter address, because the parameter value can be obtained after obtaining the parameter address and then combining the parameter type.
4. Use the va_start macro to initialize the va_list type variable defined in 3,
5. Use the va_arg macro to obtain the value of the next parameter.
6. Set the end condition.
Example program:
1 # include <stdio. h>
2 # include <stdarg. h> // required by variable argument list
3
4 void simple_va_function (INT start ,){
5 va_list arg_ptr;
6 int nargvalue = start;
7 int nargcount = 0; // count of arguments
8 va_start (arg_ptr, start); // to obtain beginning address of Variable Arguments base on the given arguemnt
9 do {
10 nargcount ++;
11 printf ("the % d argument is % d. \ n", nargcount, nargvalue );
12 nargvalue = va_arg (arg_ptr, INT );
13} while (nargvalue! =-1 );
14 va_end (arg_ptr );
15 return;
16}
17
18int main (){
19 simple_va_function (1, 2, 3, 4,-1); // need to set a flag to specify the end of argument list
20 return 0;
21}
Third: the compiler implementation principle of variable parameters, the implementation of these macros.
First, list the macro definitions in stdarg. H (note that this macro definition is related to the hardware platform and compiler. Here is the macro definition of vc6 ):
Typedef char * va_list;
# DEFINE _ intsizeof (N) (sizeof (n) + sizeof (INT)-1 )&~ (Sizeof (INT)-1 ))
# Define va_start (AP, V) (AP = (va_list) & V + _ intsizeof (v ))
# Define va_arg (AP, t) (* (T *) (AP + = _ intsizeof (t)-_ intsizeof (t )))
# Define va_end (AP) (AP = (va_list) 0)
Specifically, va_list is set as a general pointer. Some machines use void * and some use char.
_ Intszeof (n) is to take into account the space occupied by the memory alignment variables. Let's take a look at it and calculate it based on the types smaller than 4 bytes, on this platform (32-bit host), the memory is aligned to 4 bytes.
Va_start is the address for obtaining the first variable parameter.
Va_arg is the value for storing the address of the next variable parameter.
Va_end simply sets the pointer to zero.
Fourth: Summary
1. The three Macros in the Standard C library are used only to determine the memory address of each parameter in the Variable Parameter List. The Compiler does not know the actual number of parameters.
2. in actual application code, the programmer must consider how to determine the number of parameters.
1) set the flag with fixed parameters. For example, if printf is implemented, the number of % numbers indicates the number of subsequent parameters.
2) set a variable parameter to end the parameter list.
3. The key to variable parameters is to find a way to get the address of each parameter. The method to get the address is determined by the following factors:
① Function stack growth direction
② Input stack order of parameters
③ CPU alignment
④ Memory address expression, using void * to indicate the general address or char *
Combined with the source code, we can see that the implementation of va_list is determined by ④, and the introduction of _ intsizeof (n) is determined by ③, he and ① (2) jointly determine the implementation of va_start. Finally, the existence of va_end is a reflection of a good programming style, and the pointer that is no longer used is set to null, which can prevent future misoperations.