Original address: http://blog.csdn.net/morewindows/article/details/6707662
Variable parameter means that the number of parameters can change, can be less, also indicates that the type of the parameter can also change, can be int,double can also be char*, class, struct and so on. Variable parameters are the key to implementing functions such as printf (), sprintf (), or you can use variable parameters to sum any number of data to make the average easier (otherwise, use an array or write an overload of each). There is a special keyword parame in C #, but there is no similar syntax in c,c++, but fortunately it provides a handler for this, and this article focuses on how to use these functions.
The first step variable parameter representation
With three points ... To represent, view the declaration of the printf () function and the scanf () function:
int printf (const char *, ...);
int scanf (const char *, ...);
These three points are used in the macro as the variable parameter macro (Variadic Macros), and the default name is __va_args__. Such as:
#define WriteLine (...) {printf (__va_args__); Putchar (' \ n ');}
Re-WriteLine ("Morewindows");
Consider that the return value of printf () is the number of bytes representing the output. Change the macro above to:
#define WriteLine (...) printf (__va_args__) + (Putchar (' \ n ')! = EOF? 1:0);
This allows you to get the return value of the WriteLine macro, which returns the number of bytes of output, including the last ' \ n '. Both I and J will output 12 as shown in the following example.
int i = WriteLine ("Morewindows");
WriteLine ("%d", I);
Int J = printf ("%s\n", "morewindows");
WriteLine ("%d", j);
Second step how to handle the Va_list type
Variable parameters are handled internally by Va_list and the three macros associated with it, which is the key to implementing the parameter parameters.
The definition of va_list can be found in <stdarg.h>:
typedef char * VA_LIST;
Introduce the following three macros closely related to it: Va_start (), Va_end (), and Va_arg ().
The definition of these three macros can also be found in <stdarg.h>:
#define VA_START (AP,V) (AP = (va_list) &v + _intsizeof (v))
#define VA_END (AP) (AP = (va_list) 0)
#define VA_ARG (Ap,t) (* (t *) (AP + = _intsizeof (t))-_intsizeof (t)))
The _intsizeof macros used here are defined as follows:
#define _INTSIZEOF (N) ((sizeof (n) + sizeof (int)-1) & ~ (sizeof (int)-1))
To analyze these four macros:
The simplest of va_end (AP) is to place the pointer null.
AP = (va_list) &v + _intsizeof (v) in Va_start (AP,V) first takes the address of V plus _intsizeof (v). _intsizeof (v) is a little bit more complicated. (sizeof (n) + sizeof (int)-1) & ~ (sizeof (int)-1) is a bit operation, looks a bit troublesome, not really, very simple, is to take the whole to sizeof (int). For example, sizeof (int) for 4,1,2,3,4 take 4,5,6,7,8 to take 8. The arithmetic expression of the C language for X-N Rounding is ((x+n-1)/n) *n, when the power of N is 2, the last two steps can be replaced by a bitwise operation-the lowest n-1 bits clear 0.
Va_arg (ap,t) is to remove data of type T from the AP and move the pointer back accordingly. such as Va_arg (AP, int) means to take out an int data and move the pointer four bytes.
Therefore, in the function first use Va_start () to get the starting address of the variable parameter, and then use Va_arg () a value, and finally with the va_end () to resolve the variable parameters.
The third step vfprintf () function and the vsprintf () function
vfprintf () This function is important, and it is known from the name that it is very much associated with the frequently used printf () function. It has more than one overloaded version, which explains one of the most common:
Function prototypes
int vfprintf (
FILE *stream,
const Char *format,
Va_list argptr
);
The first parameter is a file pointer. File structures are necessary for reading and writing files in the C language. The incoming stdout to the screen output.
The second parameter specifies the format of the output.
The third parameter is the va_list type, which is rare, but is actually a char* representing the starting address of the variable parameter.
Return value: The number of bytes that succeeded in returning the output (not including the last ' \ '), which failed to return-1.
vsprintf () is similar to the above function and lists only the function prototypes:
int vsprintf (
Char *buffer,
const Char *format,
Va_list argptr
);
There is also an int _vscprintf (const char *format, va_list argptr), which can be used to calculate the number of bytes of buffer string in the vsprintf () function.
code example
The following is an implementation of the printf () function (note 1) and the WriteLine () function
int Printf (char *pszformat, ...)
{
Va_list parglist;
Va_start (Parglist, Pszformat);
int nbytewrite = vfprintf (stdout, Pszformat, parglist);
Va_end (parglist);
return nbytewrite;
}
int WriteLine (char *pszformat, ...)
{
Va_list parglist;
Va_start (Parglist, Pszformat);
int nbytewrite = vfprintf (stdout, Pszformat, parglist);
if (nbytewrite! =-1)
Putchar (' \ n '); NOTE 2
Va_end (parglist);
return (Nbytewrite = =-1 -1:nbytewrite + 1);
}
The call is the same as the printf () function.
Given a variable parameter to sum, unfortunately in the c,c++ can not determine the number of variable parameters passed (in printf () by scanning '% ' number to the number of actual parameters), so either to specify the number, or at the end of the parameter to set the Sentinel value:
Set Sentinel Value:
const int guardnumber = 0; Sentinel logo
The number of parameter parameters can not be determined, in printf () is by scanning the '% ' number, in this by setting the Sentinel identification to determine the parameters of the parameter termination
int MySum (int i, ...)
{
int sum = i;
Va_list argptr;
Va_start (argptr, i);
while ((i = Va_arg (argptr, int))! = Guardnumber)
sum + = i;
Va_end (ARGPTR);
return sum;
}
Such calls can be: printf ("%d\n", MySum (1, 3, 5, 7, 9, 0));
But it is not possible to pass directly to a 0:printf ("%d\n", MySum (0)); Error
Specify the number of:
int MySum (int ncount, ...)
{
if (ncount <= 0)
return 0;
int sum = 0;
Va_list argptr;
Va_start (Argptr, ncount);
for (int i = 0; i < ncount; i++)
Sum + = Va_arg (argptr, int);
Va_end (ARGPTR);
return sum;
}
When called, the first parameter indicates the number of subsequent arguments, such as:
printf ("%d\n", MySum (5, 1, 3, 5, 7, 9));
printf ("%d\n", MySum (0));
Header files used by the code:
#include <stdarg.h>
#include <stdio.h>
The use of variable parameters is far more than the above, but in the c,c++ use of variable parameters should be careful, in the use of printf () functions such as the number of parameters passed must not be less than the '% ' sign in the preceding format string, otherwise it will result in access, bad luck will also cause the program crashes.
The prototype of the variable parameter involves the problem of the stack of parameters when calling the function, this next time open a special discussion.
Note 1. There are no vfprintf () on the Internet to implement printf (), but few can make the function and printf () similar (actually fully familiar with printf () people are not much, do not believe the words can first look at "C Traps and Defects" understanding printf () Many less common parameters, and then go to Microsoft Visual STUDIO\VC98\CRT\SRC to see Output.c's implementation of printf ().
Note 2. If the output of a single character Putchar (CH) is much more efficient than printf ("%c", ch). In the case of a string that is not long, multiple calls to Putchar () will also be more efficient than calling printf ("%s\n", szstr). It is very noticeable when a function is called in large numbers.
Using variable parameters in C + +