Use of variable parameters in C language (reproduced)
Usage of variable parameters in C language
We encounter some variable variable functions in C language programming, such as Printf ()
This function, its definition is like this:
INT Printf (const char * format, ...);
In addition to having a parameter Format fixation, the number and type of the parameters of the back is
Variable, for example, we can have the following different call methods:
Printf ("% d", i);
Printf ("% s", s);
Printf ("THE NUMBER IS% D, String IS:% S", I, S);
How to write variable parameters and how the function compiler of these variable parameters is
Now? This article conducts some discussions on this issue, hoping to have some help to everyone. Will C
Netizens know that these issues do not exist in C , because C has polymorphism. But C is a C
Overcoming, the following techniques can also be used in C programs. Limited to my own level, if there is
Inappropriate, please correct it.
(1) Write a simple variable parameter C function
Let's explore how to write a C function of a simple variable parameter. Write variable parameters
The C function is to be used in the program to the following macros:
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 parameters).
These macros are defined in stdarg.h, so the program for variable parameters should contain this
Header file. Let's write a function of a simple variable parameter, the change function has at least one integer
Parameters, the second parameter is also an integer, which is optional. Function is just the value of these two parameters.
Void Simple_VA_FUN (INT i, ...)
{
VA_LIST ARG_PTR;
INT j = 0;
VA_START (Arg_PTR, I);
J = VA_ARG (Arg_Ptr, Int);
VA_END (Arg_PTR);
Printf ("% D% D / N", I, J);
Return;
}
We can declare our functions in our header:
EXTERN VOID SIMPLE_VA_FUN (INT I, ...);
We can call this in the program:
SIMPLE_VA_FUN (100);
SIMPLE_VA_FUN (100,200);
As can be seen from this function, we should use variable parameters to follow these steps:
1) First define a VA_LIST type variable in the function, here is Arg_Ptr, this change
The amount is a pointer to the parameter.
2) Then use the VA_Start macro to initialize the variable Arg_Ptr, the second parameter of this macro is the first
The previous parameter of a variable parameter is a fixed parameter.
3) Then return the variable parameters with VA_ARG and assign the value to the integer J. VA_ARG second
The parameter is the type of parameters you want to return, here is an INT type.
4) Finally, use the VA_END macro to end the acquisition of variable parameters. Then you can make it in the function
Use the second parameter. If the function has multiple variable parameters, call VA_ARG sequentially
Take each parameter.
If we call the following three methods, we are legal, but the result is not the same:
1) Simple_va_fun (100);
The result is: 100 -123456789 (changed value)
2) Simple_va_fun (100,200);
The result is: 100 200
3) Simple_va_fun (100, 200, 300);
The result is: 100 200
We see that the first call has an error, the second call is correct, the third call despite the result
Correct, but the initial design of our function has conflicts. Let's explore these results below
The reasons and variable parameters are processed in the compiler.
(2) Processing of variable parameters in the compiler
We know va_start, va_arg, va_end is defined in stdarg.h,
Due to the difference between the hardware platform 2) The compiler is different, the defined macro is different. The following is an excerpt from the macro definition of the X86 platform in VC (the '/' represents the folded):
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)
Definition _intsizeOf (n) is mainly for some of the system that requires memory. C language letters
The number is to press the stack from the right direction left, and Figure (1) is the distribution position of the function of the function in the stack. I
We see that VA_LIST is defined as a char *, some platforms or operating systems are defined as void *.
Look at the definition of va_start, defined as & V _intsizeof (v), and & V is a fixed parameter in the stack
Address, after we run Va_Start (ap, v), the AP points to the first variable parameter in the heap.
The address of the stack, as shown in the figure:
High address | ----------------------------- |
| Function Return Address |
| ----------------------------- |
| .......
| ----------------------------- |
| Nth parameter (first variable parameter) |
| ----------------------------- | <- VA_START after the AP point
| Nth-1 parameter (last fixed parameter) |
Low address | ----------------------------- | <& V
figure 1 )
Then, we use VA_ARG () to acquire the variable parameter value of Type T, and the above example is an example, I
Take a look at the return value of VA_ARG to take the INT type:
J = (* (INT *) ((AP = _INTSIZEOF (int)) -_ tentizeof (int)));
First AP = SIZEOF (int), has pointed to the address of the next parameter. Then return
AP-SIZEOF (int) INT * pointer, this is the address of the first variable parameter in the stack
(Figure 2). Then use * to obtain the content (parameter value) of this address (parameter value) to j.
High address | ----------------------------- |
| Function Return Address |
| ----------------------------- |
| .......
| ----------------------------- | <- va_arg after the AP
| Nth parameter (first variable parameter) |
| ----------------------------- | <- VA_START after the AP point
| Nth-1 parameter (last fixed parameter) |
Low address | ----------------------------- | <& V
figure 2 )
The last thing to say is the meaning of VA_END macro. The X86 platform is defined as AP = (char *) 0; making the AP no longer
Point to the stack, but the same as NULL. Some direct definitions ((void *) 0), so the compiler is not
The code will be generated for VA_END, such as the GCC's X86 platform in Linux is defined.
Here everyone should pay attention to a question: Since the address of the parameter is used for VA_START macro,
The parameters cannot be declared as register variables or as a function or array type.
About VA_START, VA_ARG, VA_END's description is these, we have to pay attention to
It is different from different operating systems and hardware platforms, but the principle is similar.
(3) Problems that variable parameters should pay attention to in programming
Because va_start, va_arg, va_end, etc., it is very stupid, the type and number of variable parameters are completely controlled by program code in this function, it does not intelligently
Identify the number and type of different parameters.
Some people will ask: So do you really have intelligent identification parameters in Printf? That's because functions
Printf is a type of parameter from a fixed parameter format string, and then calls VA_ARG
Obtain variable parameters. That is, if you want to achieve intelligent identification, you want to pass.
It is achieved by judging in your own program.
There is another problem because the compiler is not strict enough for the prototype check of the function of variable parameters.
Grid, the programming is unfavorable. If simple_va_fun () is changed to:
Void Simple_VA_FUN (INT i, ...)
{
VA_LIST ARG_PTR;
Char * s = NULL;
VA_START (Arg_PTR, I);
S = VA_ARG (arg_ptr, char *);
VA_END (Arg_PTR);
Printf ("% D% S / N", I, S);
Return;
}
Variable parameters are char * type, when we forget to call this function with two parameters, it will appear
Core Dump (UNIX) or page illegal errors (Window platform). But may not
Wrong, but the error is difficult to find, which is not conducive to us to write high quality programs.
The compatibility of the VA series macro will be mentioned below.
System v Unix defines va_start to macros with only one parameter:
va_start (VA_LIST ARG_PTR);
And ANSI C is defined as:
VA_START (VA_LIST ARG_PTR, PREV_PARAM);
If we need to define the definition of System V, we should use the varial header.
Macro, ANSI C macro, the macro of System V is incompatible, we usually use ANSI C, so
It is enough to define the ANSI C and facilitate the transplantation of the program.
summary:
The principle of variable parameters is actually very simple, and the VA series is defined by macro definition.
I am related to the stack. When we write a variable function C function, it is advantageous to have a disadvantage.
To do this, we don't need to use variable parameters. If you are in C , we should use C more
The functionality of the variable parameters is achieved to avoid using a C language.
When writing this article, you can have a cold, you have to have her care, and I would like to dedicate this article to her ...
Author: kevintz