1. Variable Parameter functions:
This is a function with an indefinite number of parameters and types. The most common function is printf;
2. header file:
In earlier versions, the header file name for UNIX System V compatibility was <varargs. h>, and the ANSI standard specified the header file name <stdarg. h>. GCC no longer supports include varargs. H files.
3. macro definition:
va_list(), va_arg(), va_start(), va_end();
4. source code example:
<Linux kernel version 3.0> printk () source code (delete ):
asmlinkage int printk(const char *fmt, ...){va_list args;int r;va_start(args, fmt);r = vprintk(fmt, args);va_end(args);return r;}
Where,...Variable parameter.
The general process is:
(1) Declare the va_list variable ARGs, where the va_list type is char *;
typedef char *va_list;
(2) Call the va_starts (ARGs, FMT) function to obtain the first parameter address of the Variable Parameter following the FMT parameter;
va_start(args, fmt);
(3) Call the subfunction vprintk ()
(4) Call the va_end (ARGs) function to point Arg to null
5. macro definition analysis
The macro definition of va_start is as follows:
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
The _ BND macro is defined:
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
The function of _ BND (x, BND) is to return the size of space occupied by the X type after alignment by the current machine: When alignment by four bytes, the value of _ aupbnd is 3, if the X type is smaller than 4, the occupied space is 4. If the X type is greater than 4, the return value is an integer multiple of 4.
When a function is called, the parameter stack entry sequence is from right to left, while the stack space address is extended downward. Therefore, the parameter from the leftmost to the rightmost is a memory with a continuously increasing address. Therefore, the va_start macro is used to point the AP pointer to the first parameter after a fixed parameter (char * FMT.
After pointing to the first parameter, you can call the macro va_arg () to obtain the next parameter address, which is defined as follows:
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
First, point the AP address to the next parameter address, and then the expression returns the value of the first parameter.
The va_end macro definition is simple:
#define va_end(ap) (void) 0
In this version definition, va_end does not perform any operations. It is generally considered that the AP pointer must be pointed to NULL:
# Define va_end (AP) AP = (char *) 0
In this way, the "wild pointer" is eliminated in the code ".
6. Example
Function: implements a function that calculates the sum of squares of several numbers. There is at least one parameter, and the end mark of the parameter is A-1 parameter. The reason for the existence of the flag is that the Variable Parameter Function cannot determine when to stop reading the function.
The function code is as follows:
int sum_square(int n,...){int k = 0;int temp =0;va_list args;if(n == -1){return 0;}va_start(args,n);k+= n*n;while((temp=va_arg(args,int)) != -1){k+= temp * temp;}va_end(args);return k;}
If the function call does not have the-1 parameter, unexpected results may occur. This is generally caused by a "segment error" caused by access to invalid memory ".
printf("sum of square is %d \n",sum_square(1,2,3,4,-1));
After running:
Sum of Square is 30