The variable parameter means that the number of parameters can change, can be more or less, also indicate the types of parameters can also change, can be int,double can also be char*, class, structure and so on. A variable parameter is the key to implementing a function such as printf (), sprintf (), or you can sum any number of data with a variable parameter, which is convenient for averaging (otherwise, an array or each type of overload is written). There are specialized keyword parame in C #, but there is no similar syntax in c,c++, but fortunately this is provided, and this article focuses on how to work with these functions.
First step variable parameter representation
With three points ... To view the declarations of the printf () function and the scanf () function:
int printf (const char *, ...);
int scanf (const char *, ...);
The three points used in macros are variable parameter macros (Variadic Macros), and the default name is __va_args__. Such as:
#define WriteLine (...) {printf (__va_args__); Putchar (' \ n ');}
Again 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 in the output, including the last ' \ n '. I and J will output 12 as shown in the following example.
Copy Code code as follows:
int i = WriteLine ("Morewindows");
WriteLine ("%d", I);
Int J = printf ("%s\n", "morewindows");
WriteLine ("%d", j);
Step two: How to deal with Va_list types
In the function, the variable parameter is treated with va_list and three macros related to it, which is the key to the parameter of variable parameter.
The definition of va_list can be found in <stdarg.h>:
typedef char * VA_LIST;
Then introduce the three macros that are 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 macro used is defined as follows:
#define _INTSIZEOF (n) ((sizeof (n) + sizeof (int)-1) & ~ (sizeof (int)-1))
To analyze these four macros:
The simplest way to Va_end (AP) is to set the pointer to null.
The 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 complicated. ((sizeof (n) + sizeof (int)-1) & ~ (sizeof (int)-1)) are all bit-operated and seem to be a bit of a hassle, but it's very simple to take the whole to sizeof (int). For example, sizeof (int) for 4,1,2,3,4 take the 4,5,6,7,8 to take 8. The arithmetic expression of the C language for X to N is ((x+n-1)/n) *n, when the power of N is 2, the last two-step operation can be changed to bitwise operation-the lowest n-1 bits 0 is OK.
Va_arg (ap,t) is the data that takes the type T from the AP, and then moves the pointer accordingly. such as Va_arg (AP, int) means that an int data is removed and the pointer is moved four bytes.
Therefore, in the function, we first use the Va_start () to get the starting address of the variable parameter, then use the Va_arg () one to take the value, and then the Va_end () end can be used to resolve the variable parameter.
Step three vfprintf () function and vsprintf () function
vfprintf () This function is very important, the light from the name to see that it is often used in the printf () function has a great relationship. It has multiple overloaded versions, which are explained in the most common:
Function prototypes
Copy Code code as follows:
int vfprintf (
FILE *stream,
const Char *format,
Va_list argptr
);
The first parameter is a file pointer. The file structure is necessary for reading and writing files in C language. To pass the 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 argument.
return Value:The number of bytes that successfully returned the output (excluding the last ' ""), and the failure returns-1.
vsprintf (), like the function above, lists only the function prototypes:
Copy Code code as follows:
int vsprintf (
Char *buffer,
const Char *format,
Va_list argptr
);
There is also an int _vscprintf (const char *format, va_list argptr), a space that can be used to calculate how many bytes the buffer string in the vsprintf () function will take.
code example
The following is an implementation of the printf () function (note 1) and the WriteLine () function
Copy Code code as follows:
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.
Then give a sum with variable parameters, unfortunately in c,c++ cannot determine the number of incoming variable parameters (printf () by scanning the number of '% ' to exact the number of parameters), so either specify the number, or set the Sentinel value at the end of the argument:
Set Sentinel values:
Copy Code code as follows:
const int guardnumber = 0; Sentinel logo
The number of parameter parameters cannot be determined in printf () by scanning the number of '% ', in which the termination of parameter parameters is determined by setting Sentinel ID
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;
}
This can be called: printf ("%d\n", MySum (1, 3, 5, 7, 9, 0));
However, it is not possible to pass directly into a 0:printf ("%d\n", MySum (0)); Error
Number specified:
Copy Code code as follows:
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 represents the number of subsequent arguments, such as:
printf ("%d\n", MySum (5, 1, 3, 5, 7, 9));
printf ("%d\n", MySum (0));
header file used by code:
#include <stdarg.h>
#include <stdio.h>
The use of variable parameters is much more than the above several however, be careful when using variable parameters in c,c++, the number of arguments passed in using printf () must not be less than the number of '% ' symbols in the previous formatted string, or it will result in a access violation, and bad luck can cause the program to crash.
The prototype of the variable parameter involves the problem of the stack of parameters when calling the function, and the next time we open a special discussion.
Note 1. There are not many people on the Internet that do not vfprintf () their own parsing parameters to achieve printf (), but rarely have the functionality to be similar to printf (in fact fully familiar with printf () is not much, do not believe that you can see "C Traps and defects" understand printf ( Many of the less commonly used parameters, and then go to Microsoft Visual STUDIO\VC98\CRT\SRC to see the output.c implementation of printf ().
Note 2. outputting a single character putchar (CH) is more efficient than printf ("%c", ch). In cases where the string is not long, calling Putchar () multiple times is more efficient than calling printf ("%s\n", szstr). Very obvious when a function is called in large numbers.