Recently, in variable parameters of egg pain, please wait ....
Note: Because the parameter address is used in the va_start macro, the parameter cannot be declared as a register variable or as a function or array type.
Notes for using va_list:
(1) Because va_start, va_arg, va_end, and so on are defined as macros, it seems stupid. the types and numbers of variable parameters are completely defined by the functionProgramCodeIt cannot intelligently identify the number and type of different parameters. That is to say, if you want to intelligently identify variable parameters, you need to make judgments in your own program.
(2) another problem is that the compiler does not strictly check the prototype of the Variable Parameter Function, which is unfavorable for programming errors. It is not conducive to writing high-quality code.
Summary: The function principle of variable parameters is actually very simple, and the VA series are defined by Macro. Implementation is related to the stack. When writing a variable function's c function, it has both advantages and disadvantages. Therefore, we do not need to use variable parameters unless necessary. If in C ++, we should use C ++ polymorphism to implement variable parameter functions and avoid using C language as much as possible.
Summary
Http://blog.sina.com.cn/s/blog_477815290100cxtk.html
Principles:
Va_list is a set of macros that solve the variable parameters problem in C language, under the header file <stdarg. h>.
Usage of va_list:
(1) first define a va_list variable in the function. This variable is a pointer to the parameter.
(2) then use the va_start macro to initialize the va_list variable just defined in the variable. The second parameter of this macro is the first parameter of the first variable parameter and is a fixed parameter.
(3) then use va_arg to return variable parameters. The second parameter of va_arg is the type of the parameter to be returned.
(4) use the va_end macro to end the variable parameter acquisition. Then you can use the second parameter in the function. If a function has multiple variable parameters, call va_arg to obtain the parameters.
Processing of va_list In the compiler:
(1) After running va_start (AP, V), the AP points to the address of the first variable parameter on the stack.
(2) va_arg () gets the variable parameter value of type T. In this step, APT = sizeof (T type) First, let the AP point to the address of the next parameter. Then return the T type * pointer of AP-sizeof (T type), which is the address of the first variable parameter in the stack. Then use * to get the content of this address.
(3) va_end (). The X86 platform is defined as AP = (char *) 0), so that the AP no longer points to the stack, but is the same as null, some are directly defined as (void *) 0, so that the compiler will not generate code for va_end. For example, GCC is defined in this way on the Linux X86 platform.
Note: Because the parameter address is used in the va_start macro, the parameter cannot be declared as a register variable or as a function or array type.
Notes for using va_list:
(1) Because va_start, va_arg, va_end, and so on are defined as macros, it seems stupid. the types and numbers of variable parameters are completely controlled by the program code in this function, it cannot intelligently identify the number and type of different parameters. that is to say, if you want to implement Intelligent Identification of variable parameters, you must make judgments in your own programs.
(2) another problem is that the compiler does not strictly check the prototype of the Variable Parameter Function, which is unfavorable for programming errors. It is not conducive to writing high-quality code.
Summary: The function principle of variable parameters is actually very simple, and the VA series are defined by Macro. Implementation is related to the stack. When writing a variable function's c function, it has both advantages and disadvantages. Therefore, we do not need to use variable parameters unless necessary. If in C ++, we should use C ++ polymorphism to implement variable parameter functions and avoid using C language as much as possible.
Va_list AP; // declare a variable to convert the parameter list
Va_start (AP, FMT); // initialize the variable
Va_end (AP); // end Variable list, which is used in pairs with va_start.
Parameters can be retrieved Based on va_arg (AP, type)
Output programs that have been successfully debugged
# Include <stdio. h>
# Include <stdarg. h>
# Define bufsize 80
Char buffer [bufsize];
Int vspf (char * FMT ,...)
{
Va_list argptr;
Int CNT;
Va_start (argptr, FMT );
CNT = vsnprintf (buffer, bufsize, FMT, argptr );
Va_end (argptr );
Return (CNT );
}
Int main (void)
{
Int inumber = 30;
Float fnumber = 90.0;
Char string [4] = "ABC ";
Vspf ("% d % F % s", inumber, fnumber, string );
Printf ("% s \ n", buffer );
Return 0;
}
Vsnprintf: int vsnprintf (char * STR, size_t size, const char * format, va_list AP );
Write output to character sting Str
Return Value: the number of characters
Printed (not including the trailing '\ 0' used to end output to strings ). the functions snprintf () and vsnprintf () do not write more than size bytes (including the trailing '\ 0 '). if the output was truncated due to this limit then the return value is the number of characters (not including the trailing '\ 0 ') which wocould have been written to the final string if enough space had been available. thus, a return value of size or more means that the output was truncated. if an output error is encountered, a negative
Value is returned.
If (return_value>-1)
Size = n + 1;
Else
Size * = 2;
The glibc implementation of the functions snprintf () and vsnprintf () conforms to the c99 standard, I. E ., behaves as described abve, since glibc version 2.1. until glibc 2.0.6 they wocould return-1 when the out put was truncated.
The C language uses macros such as va_start to process these variable parameters. These macros seem complicated. In fact, the principle is quite simple, that is, according to the characteristics of the parameter stack, the addresses of each variable parameter are obtained starting from the fixed parameter closest to the first variable parameter. Next we will analyze these macros. In the stdarg. h header file, there are different macro definitions for different platforms. We select the macro definition under the x86 Platform:
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)
_ Intsizeof (n) macro is used to consider the systems whose memory addresses need to be aligned. The macro name should be aligned with sizeof (INT. Generally, sizeof (INT) = 4, that is, the address of the parameter in the memory is a multiple of 4. For example, if sizeof (n) is between 1 and 4, _ intsizeof (n) = 4; If sizeof (n) is between 5 and 8, _ intsizeof (n) = 8.
To obtain each variable parameter from a fixed parameter in sequence, va_start and va_arg make full use of the following two points:
1. When using C language for function calling, first press the last parameter to the stack
2. The memory allocation sequence on the X86 platform is from high-address memory to low-address memory.
High address
Nth Variable Parameter
...
Second Variable Parameter
The first variable parameter? AP
Fixed parameter? V
Low-end address
It can be seen that V is the address of a fixed parameter in the memory. After va_start is called, the AP points to the first variable parameter. This macro is used to increase the memory size occupied by V on the memory address of V, so that the address of the first variable parameter is obtained.
Next, we can imagine that if I can determine the type of this variable parameter, then I will know how much memory it occupies, and I will be able to get the address of the next variable parameter.
Let's take a look at va_arg. It first points AP to the next variable parameter, and then deducts the size of the current variable parameter to get the memory address of the current variable parameter. Then, it performs a type conversion and returns its value.
To determine the type of each variable parameter, either the default type or the fixed parameter contains enough information so that the program can determine the type of each variable parameter. For example, in printf, the program analyzes the format string to determine the large type of each variable parameter.
The last macro is simple. va_end makes the AP no longer point to a valid memory address.
In fact, in varargs. the H header file defines the VA series macros implemented by UNIX System V. the H header file defines Macros in the ansi c format. These two macros are incompatible. Generally, we should use va Macros in the ansi c format.
Definition _ intsizeof (n) is mainly for some systems that require memory alignment. C language functions are pushed from right to left into the stack, and function parameters are distributed in the stack. I
We can see that va_list is defined as char *, and some platforms or operating systems are defined as void *. let's look at the definition of va_start, which is defined as & V + _ intsizeof (V), while & V is a fixed parameter in the stack.
So after we run va_start (AP, V), the AP points to the address of the first variable parameter on the stack:
High address | ----------------------------- |
| Function return address |
| ----------------------------- |
| ...... |
| ----------------------------- |
| Nth parameter (the first variable parameter) |
| ----------------------------- | <-- After va_start, the AP points
| N-1 parameter (the last fixed parameter) |
Low address | ----------------------------- | <-- & V
Then, we use va_arg () to obtain the variable parameter value of type T. The preceding example is int type. Let's take a look at the return value of the va_arg type:
J = (* (int *) (AP + = _ intsizeof (INT)-_ intsizeof (INT); First ap + = sizeof (INT ), the address that points to the next parameter. then return
AP-sizeof (INT) int * pointer, which is the address of the first variable parameter in the stack
Then, use * to get the content of this address (parameter value) and assign it to J.
High address | ----------------------------- |
| Function return address |
| ----------------------------- |
| ...... |
| ----------------------------- | <-- Va_arg
| Nth parameter (the first variable parameter) |
| ----------------------------- | <-- After va_start, the AP points
| N-1 parameter (the last fixed parameter) |
Low address | ----------------------------- | <-- & V
The last thing we want to talk about is the va_end macro. The X86 platform is defined as AP = (char *) 0, so that the AP no longer points to the stack, but is the same as null. some are directly defined as (void *) 0, so the compiler does not
Code is generated for va_end. For example, GCC is defined in this way on the x86 Platform of Linux. you should pay attention to one problem: Because the address of the parameter is used in the va_start macro, the parameter cannot be declared as a register variable or as a function or array type. this is the description of va_start, va_arg, and va_end. We should note that different operating systems and hardware platforms have different definitions, but their principles are similar.
System v unix defines va_start as a macro with only one parameter:
Va_start (va_list arg_ptr );
Ansi c is defined:
Va_start (va_list arg_ptr, prev_param );
If we want to use the definition of System V, we should use
Macros and ansi c macros are incompatible with system v macros. We generally use ansi c, so
It is enough to use the definition of ansi c to facilitate program transplantation.
The function principle of variable parameters is actually very simple, and the VA series are defined by macro, implementation is related to the stack. when we write a variable function's c function, it has both advantages and disadvantages. Therefore, we do not need to use variable parameters unless necessary. in C ++, we should use C ++ polymorphism to implement variable parameter functions, and try to avoid using C language.
Another statement from csdn ..
Int snprintf (char * STR, size_t size, const char * format ,...);
Int vsnprintf (char * STR, size_t size, const char * format, va_list AP );
=
Big difference
You can use variable parameters in snprintf.
Vsnprintf is rarely directly used, but called within a function with an indefinite parameter.