Preface:
This article is adapted from the article "Variable Parameter usage in C Language" by kevintz, a netizen. before writing this article, I would like to express my sincere respect and thanks to this predecessor.
1. What are variable parameters?
In C language programming, we sometimes encounter some functions with variable parameter numbers, such as the printf () function. Its prototype is:
Int printf (const char * format ,...);
In addition to the fixed format parameter, the number and type of parameters that follow are variable (with three vertices "…" Parameter placeholder), the actual call can be in the following form:
Printf ("% d", I );
Printf ("% s", S );
Printf ("the number is % d, string is: % s", I, S );
These are already familiar to everyone. However, the question of how to write variable parameters to C functions and how to implement these Variable Parameter Function compilers has been bothering me for a long time. This article will discuss this issue and hope to help you.
2. Write a simple variable parameter C function
First look at the example program. This function has at least one integer parameter, followed by a placeholder ..., In this example, all input parameters must be integers. The function is to print the values of all parameters.
The function code is as follows:
// Example code 1: use of variable parameter functions
# Include "stdio. H"
# Include "stdarg. H"
Void simple_va_fun (INT start ,...)
{
Va_list arg_ptr;
Int nargvalue = start;
Int nargcout = 0; // number of variable parameters
Va_start (arg_ptr, start); // determine the memory start address of the Variable Parameter Based on the fixed parameter address.
Do
{
++ Nargcout;
Printf ("the % d th Arg: % d/N", nargcout, nargvalue); // output the values of each parameter
Nargvalue = va_arg (arg_ptr, INT); // obtain the value of the next variable parameter.
} While (nargvalue! =-1 );
Va_end (arg_ptr );
Return;
}
Int main (INT argc, char * argv [])
{
Simple_va_fun (100,-1 );
Simple_va_fun (100,200,-1 );
Return 0;
}
From the implementation of this function, we can see that the following steps should be taken to use variable parameters:
(1) The following macros will be used in the program:
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 here is the meaning of Variable-argument (Variable Parameter.
These macros are defined in stdarg. H, so programs that use variable parameters should include this header file.
(2) The function first defines a va_list variable. Here it is arg_ptr, which is a pointer to the parameter address. the parameter value can be obtained only after obtaining the parameter address and combining the parameter type.
(3) Use the va_start macro to initialize the variable arg_ptr defined in (2). The second parameter of this macro is the previous parameter in the variable parameter list, that is, the last fixed parameter.
(4) use the va_arg macro in sequence to make arg_ptr return the address of the Variable Parameter. After this address is obtained, the parameter value can be obtained based on the parameter type. Then output.
The condition indicates whether the parameter value is-1. Note that the called function does not know the correct number of variable parameters when calling. The programmer must specify the end condition in the code. As to why it does not know the number of parameters, the reader will naturally understand after reading the internal implementation mechanisms of the following macros.
Variable parameters of functions in C Language
1. To use parameters in a function, you must first include <stdarg. h>, # inlcude <stdarg. h>
2. The stdarg. h header file contains the following macro definitions:
Void va_start (va_list AP, last );
Type va_arg (va_list AP, type );
Void va_end (va_list AP );
Void va_copy (va_list DEST, va_list SRC );
These macro definitions will be described in detail below
The stdarg. h header file declares a va_list type and defines three macros to traverse the variable parameter list.
A variable of the va_list type must be included in the function definition that has a variable list. This variable will be used in va_start, va_arg, and va_end.
Va_start (va_list AP, last)
Va_start must be called first. It initializes the va_list variable AP. The last parameter is the name of the previous parameter in the variable parameter list, that is, the name of the function parameter with the final type determined; because the address of this parameter may be used by the macro va_start, it is best not to use register variables, functions, or arrays.
Type va_arg (va_list AP, type)
After the macro va_arg is expanded, it is about the expression of the type and value of the next parameter. The parameter AP is the va_list type parameter initialized by va_start. The parameter type is a clear type name.
The first va_arg call after the va_start call returns the first parameter in the variable parameter list, And the next parameter (if any) in the Variable list is returned when va_arg is called again ).
If there is no next parameter, or the parameter type does not match, a random error is generated.
If the AP is passed to the va_arg function, the AP value is not defined after the function returns.
Void va_end (va_list AP)
Va_end must be called each time va_start is called. After va_end (AP) is called, the AP is not defined.
Void va_copy (va_list DEST, va_list SRC)
Copy a variable of the va_list type.
Each time va_copy is called, a corresponding va_end call is required.
3. Example:
# Include <stdio. h>
# Include <stdarg. h>
Void Foo (char * FMT ,...);
Int main ()
{
Char * string = "aaaaaaaaaaaa ";
Int I = 10;
Char c = 'V ';
Foo ("s d c", String, I, C );
Return 0;
}
Void Foo (char * FMT ,...)
{
Va_list AP;
Int D;
Char C, * P, * s;
Va_start (AP, FMT );
While (* FMT)
Switch (* FMT ++)
{
Case's ':/* string */
S = va_arg (AP, char *);
Printf ("string % s", S );
Break;
Case 'D':/* int */
D = va_arg (AP, INT );
Printf ("int % d", d );
Break;
Case 'C':/* char */
/* Need a cast here since va_arg only
Takes fully promoted types */
C = (char) va_arg (AP, INT );
Printf ("char % C", C );
Break;
Default:
Printf ("*****************************");
Break;
}
Va_end (AP );
}
(0)/comment (1) variable parameters: variable argument.
It is defined by a function with three dots '.', separated by commas (,) and other parameters.
Variable parameters have the following characteristics: they do not correspond exactly as fixed parameters do, nor do they have fixed parameter types and names. variable parameters do not contain numbers.
The input parameter can also be multiple. The type of each parameter in a variable parameter can be different or the same. Each parameter of a variable parameter does not
The actual name corresponds to it.
It can be seen that the form of variable parameters is very free and rich. For some reason, it gives those talented programmers more space to imagine and play.
However, more freedom also increases the operational difficulty.
The following describes several aspects of variable parameters. 1) Storage Format of variable parameters.
As we all know, common function parameters belong to local variables, and local variables are stored in the stack area of the memory (so-called stack zone: automatically allocated and released by the compiler,
Stores the function parameter values and local variable values. The operation method is similar to the stack in the data structure .). Variable parameters are also stored in the memory stack.
When storing the function parameters, the compiler stacks them one by one from the right to the left of the function parameters,
This ensures that the top of the stack is the first parameter of the function parameter (from left to right), while the memory allocation sequence on the 80x86 platform is from high-address memory to low-address memory.
Therefore, the form of the function parameter stored in the memory is as follows (take Fun (INT var1, int var2,..., int var3, int var4 ):
Stack zone:
| Stack top and low address
| The first fixed parameter var1
| Var2, the first fixed parameter before a Variable Parameter
| The first parameter of a Variable Parameter
|...
| Last Variable Parameter
| The second-to-last fixed parameter var3 of the Function
| Last fixed parameter var4 of the Function
|...
| Return address of the Function
|...
| High stack bottom address
2) header files and macro descriptions used for variable parameters
Here, the tc2.0 compiler is used as a reference object.
Variable parameters are defined in the header file named "stdarg. H" of tc2.0.
This file is:
/* Stdarg. h
Definitions for accessing parameters in functions that accept
A variable number of arguments.
Copyright (c) Borland International 1987,1988
All rights reserved.
*/
# If _ stdc __
# DEFINE _ cdecl
# Else
# DEFINE _ cdecl
# Endif
# If! Defined (_ stdarg)
# DEFINE _ stdarg
Typedef void * va_list;
# Define va_start (AP, parmn) (AP = ...)
# Define va_arg (AP, type) (* (type *) (AP) ++)
# Define va_end (AP)
# DEFINE _ va_ptr (...)
# Endif
The above content is "stdarg. H.
This file defines the data type used by variable parameters: typedef void * va_list;
Va_start (AP, parmn) is used for initialization. The AP points to the first parameter of the variable parameter. The AP type is va_list,
Parmn is a fixed parameter before a variable parameter.
Va_arg (AP, type) obtains the parameters that the current AP points to, and points the AP to the next parameter of a Variable Parameter. type is the type of the parameter to be obtained.
Va_end (AP) end variable parameter acquisition.
3) Instances for variable parameters
Instance objective: to use variable parameters to transmit a variable number of strings and display the passed strings.
# Include <stdio. h>
# Include <conio. h>
# Include <stdarg. h>
Void tvararg (INT num,...);/* num is the number of variable parameters */
Int main (void)
{
Clrscr ();
Tvararg (5, "Hello! "," My "," name "," is "," neverthesame./N ");
Tvararg (8, "this", "is", "an", "example", "about", "variable-argument", "in", "funtion ");
Getch ();
Return 0;
}
Void tvararg (INT num ,...)
{
Va_list argp;/* defines a variable pointing to a variable parameter */
Va_start (argp, num);/* initialization, use argp to point to the first parameter of a Variable Parameter */
While (-- num> = 0)
Printf ("% s", (va_arg (argp, char *);/* va_arg (argp, char *) Get the parameter pointed to by argp,
Use argp to point to the next parameter. char * converts the type of the obtained parameter to char .*/
Va_end (argp);/* obtain variable parameters after the end */
Return;
}
4) Notes for using variable parameters
1. Each function has at most one variable parameter.
2. In va_start (AP, parmn), parmn is a fixed parameter before the variable parameter.
3. The number of variable parameters is uncertain, and it is entirely agreed by the program.
4. the type of the variable parameter is unknown. It is completely specified by the type in va_arg (AP, type), and the type of the parameter is forcibly converted.
But does printf () Implement the identification parameter? That's because the function
Printf () is to analyze the parameter type from the fixed parameter format string, and then call va_arg
To obtain variable parameters. That is to say, if you want to intelligently identify variable parameters
Through making judgments in your own program.
5. the compiler does not strictly check the prototype of variable parameter functions, which is highly required by programmers.