Write a variable-parameter C function--the application of the macro Va_start, Va_arg and Va_end in the header file Stdarg.h

Source: Internet
Author: User

In C programming we will encounter some functions with variable number of parameters, such as printf ()
This function, which is defined as this:
int printf (const char* format, ...);
In addition to having a parameter format fixed, the number and type of arguments followed are
Variable, for example, we can have the following different invocation methods:
printf ("%d", I);
printf ("%s", s);
printf ("The number is%d, string is:%s", I, s);
How to write the C function of a mutable parameter and how the function compiler for these mutable arguments are actually
Now? This article on this question to carry on some discussion, hoped can have some help to everybody. C + +
Users know that these problems do not exist in C + + because C + + is polymorphic. But C + + is a C
Hyper-Set, the following techniques can also be used in C + + programs. Limited to my level, the text if there is
Please correct me if you are not in the wrong place.

(a) write a simple variable-parameter C function

Let's explore how to write a simple variable-parameter c function. Write variable parameters
The C function uses the following macros 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 the variable-argument (variable parameter).
These macros are defined in Stdarg.h, so a program that uses mutable parameters should contain this
Header file. Let's write a simple variable parameter function that has at least one integer
parameter, the second parameter is also an integer and is optional. The function simply prints the values of the two parameters.
void Simple_va_fun (int i, ...)
{
Va_list arg_ptr;
int j=0;

v A_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 function in our header file like this:
extern void Simple_va_fun (int i, ...);
We can call this in the program:
Simple_va_fun;
Simple_va_fun (100,200);
from the implementation of this function we can see that we should have the following steps to use mutable parameters:
1) First define a variable of type va_list in the function, here is arg_ptr, this variable
quantity 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 parameter of a variable parameter of
, is a fixed parameter.
3) Then return the variable parameters with Va_arg and assign the value to the integer J. The second
parameter of Va_arg is the type of the parameter you want to return, and this is the int type.
4) Finally, the Va_end macro is used to end the variable parameter acquisition. Then you can make
use the second argument in the function. If the function has more than one variable parameter, call Va_arg to get
to take each parameter.
If we call it in the following three ways, it is legal, but the result is different:
1) simple_va_fun (100); The
result is: 100-123456789 (variable value)
2) Simple_va_fun (100,200); The
result is: [+]
3] simple_va_fun (100,200,300); The
result is: US $
We see that the first call has an error, the second is correct, and the third call, although the result is
correct, is in conflict with the original design of our function. The following section explores the causes of these results
and how mutable parameters are handled in the compiler.

(ii) Processing of variable parameters in the compiler

We know that va_start,va_arg,va_end is defined macro in the Stdarg.h,
Because of 1) different hardware platforms 2) compilers differ, so the defined macros are also different, under
Face to VC + + in the STDARG.H x86 platform macro definition excerpt as follows ('/' indicates a fold line):

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)

The definition of _intsizeof (n) is primarily for some systems that require memory alignment. C-Language letter
The number is pressed from right to left onto the stack, and figure (1) is the position where the function's parameters are distributed in the stack. I
We see that va_list is defined as char*, and some platforms or operating systems are defined as void*.
Look at the definition of va_start, defined as &v+_intsizeof (v), while &v is a fixed parameter on the stack
Address, so after we run Va_start (AP, v), the AP points to the first mutable parameter in the heap
The address of the stack:

High Address |-----------------------------|
| function return Address |
|-----------------------------|
|....... |
|-----------------------------|
| nth parameter (first variable parameter) |
|-----------------------------|<--va_start after AP Point
| n-1 parameters (last fixed parameter) |
Low Address |-----------------------------|<--&v
Figure (1)

Then we use Va_arg () to get the variable parameter values of type T, the example of the int type, I
Let's take a look at the return value of the va_arg int:
J= (* (int*) ((AP + = _intsizeof (int))-_intsizeof (int)));
First ap+=sizeof (int), which already points to the address of the next parameter. Then return
The int* pointer to ap-sizeof (int), which is exactly the address of the first mutable parameter in the stack
(Figure 2). Then use * to get the contents of this address (parameter values) assigned to J.

High Address |-----------------------------|
| function return Address |
|-----------------------------|
|....... |
|-----------------------------|<--va_arg after AP Point
| nth parameter (first variable parameter) |
|-----------------------------|<--va_start after AP Point
| n-1 parameters (last fixed parameter) |
Low Address |-----------------------------|<--&v
Figure (2)

The last thing to say is the meaning of the Va_end macro, the x86 platform is defined as ap= (char*) 0; 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 does not
Generates code for Va_end, such as the one defined by GCC on the Linux x86 platform.
Here are a few things to note: Because the address of the parameter is used for the Va_start macro, the
A parameter cannot be declared as a register variable or as a function or an array type.
The description of Va_start, Va_arg, Va_end, that's all we have to pay attention to.
The definitions of different operating systems and hardware platforms are somewhat different, but the principles are similar.

(c) Issues to be noted in programming of variable parameters

the type and number of variable parameters are completely controlled by program code in the function, and it is not intelligent
to recognize the number and type of different parameters.
One would ask: Is it true that the intelligent identification parameters are not implemented in printf? That's because the function
printf parses the type of the parameter from the fixed parameter format string, and then calls Va_arg
to get the variable argument. That is to say, If you want to realize the intelligent identification of variable parameters, it is necessary to pass the
in their own program to make judgments to achieve.
Another problem is that the compiler is not strict enough with the prototype of the Variadic function to check for errors in the programming error. 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
}
The variable parameter is char*, and when we forget to call the function with two parameters, it appears
Core dump (Unix) or invalid page error (window platform). But it's not possible.
Wrong, but the error is difficult to find, it is not conducive to us to write high-quality programs.
The following is a reference to the compatibility of VA series macros.
System V UNIX defines va_start as a macro 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 want to use the definition of System V, we should use the Vararg.h defined in the header file.
macros, ANSI C macros are incompatible with System V macros, and we generally use ANSI C, so
The definition of ANSI C is sufficient and facilitates the porting of programs.


Summary:
The function principle of variable parameters is actually very simple, and the VA series is defined by the macro definition, the real
is now associated with the stack. When we write a variable function c function, there are pros and cons, so there's no need to
We do not need to use variable parameters. If in C + +, we should take advantage of C + + 's multi-
The ability to implement variable parameters, as far as possible to avoid the C language of the way to achieve.

Write a variable-parameter C function--the application of the macro Va_start, Va_arg and Va_end in the header file Stdarg.h

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.