Principles and instances of va_start va_arg va_end

Source: Internet
Author: User

 

Func (type para1, type para2, type para3 ,...)
{

/****** Step 1 ******/
Va_list AP;

Va_start (AP, para3); // you must specify the parameter ** ap that points to the first variable parameter after para.


/****** Step 2 ******/
// At this time, the AP points to the first variable parameter.

// Call va_arg to obtain the value

Type xx = va_arg (AP, type );


// The type must be the same, for example:
// Char * P = va_arg (AP, char *);

// Int I = va_arg (AP, INT );
// If multiple parameters continue to call va_arg

/****** Step 3 ******/
Va_end (AP); // for robust!
}

◎ Research:
Typedef char * va_list; // va_list is equivalent to char *, which is the character pointer.

# Define va_start _ crt_va_start // note the following substitution.
# Define va_arg _ crt_va_arg

# Define va_end _ crt_va_end

# DEFINE _ crt_va_start (AP, V) (AP = (va_list) _ addressof (v) + _ intsizeof (v ))

# DEFINE _ crt_va_arg (AP, t) (* (T *) (AP + = _ intsizeof (t)-_ intsizeof (t )))

# DEFINE _ crt_va_end (AP) (AP = (va_list) 0)
Va_list argptr;

C functions are pushed from right to left into the stack. After va_start is called,
According to the defined macro operation, _ addressof obtains the address of V, and then

Add the value of V to the address so that the AP points to the first variable parameter:

High stack address

| .......
| Function return address
| .......

| Last function parameter
| ....

| The first variable parameter of the function <-- after va_start, the AP points
| Last fixed parameter of the Function

| The first fixed parameter of the Function
Stack top and low address



Then, use va_arg () to obtain the variable parameter value of type T. First, let the AP point to the next parameter:

AP + = _ intsizeof (T), and then subtract _ intsizeof (T) to make the expression result

The value before the AP, that is, the address of the parameter to be obtained, is forcibly converted to the address pointing to this parameter
Type pointer, and then use *

Finally, use va_end (AP) to initialize the AP and maintain robustness.
Example :( chenguiming)

# Include <stdio. h>
# Include <ctype. h>

# Include <stdlib. h>
# Include <stdarg. h>



Int average (INT first,...) // Variable Parameter function, which is also available in C ++ **... It indicates that there are many variable parameters.

{
Int COUNT = 0, I = first, sum = 0;

Va_list maker; // all parameters of the va_list function can be saved as a list. Va_list is char *, which indicates that maker is a pointer of character type.

Va_start (maker, first); // set the starting position of the list. ** frist is just a parameter with maker, this does not mean that maker points to frist but to the first variable parameter after first, and frist is a fixed parameter because it... Before. At this time, frist points to 3.

While (I! =-1)
{
Sum + = I;

Count ++;

I = va_arg (maker, INT); // returns the current value of the maker list and points to the next position in the list.

}
// First time: I = 2, sum = 2;

Second time: I = 3, because va_start (maker, first); sum = 2 + 3 = 5; at the same time, I = va_arg (maker, INT) makes I = 4;

Third time: I = 4, sum = 5 + 4 = 9, I = 4;
The fourth I = 4, sum = 9 + 4 = 13 I =-1

Return sum/count;

}


Void main (void)
{

Printf ("average is: % d/N", average (2, 3, 4,-1 ));

}
Note that their header file stdarg.. h
STD is normal. Arg indicates a parameter;
Auxiliary understanding:

Va_start (arg_ptr, argn): sets the parameter list pointer arg_ptr to the first optional parameter in the function parameter list. Description: argn is a fixed parameter located before the first optional parameter (or, the last fixed parameter ;... The order of parameters in the function parameter list in the memory is the same as that in the function declaration. If the declaration of a va function is void va_test (char a, char B, char C ,...), Then its fixed parameters are a, B, c in sequence, and the last fixed parameter argn is C, so it is va_start (arg_ptr, c ).



Va_arg (arg_ptr, type): return the parameter indicated by the pointer arg_ptr In the parameter list. The return type is type, and the pointer arg_ptr points to the next parameter in the parameter list.



Va_copy (DEST, Src): the types of DeST and SRC are va_list. va_copy () is used to copy the parameter list pointer and initialize DEST as SRC.



Va_end (arg_ptr): clears the parameter list. The parallel parameter pointer arg_ptr is invalid. Note: After the pointer arg_ptr is set to invalid, you can restore arg_ptr by calling va_start () and va_copy. Each time va_start ()/va_copy () is called, a corresponding va_end () must match it. The parameter pointer can be freely moved back and forth in the parameter list, but must be in va_start ()... Within va_end.

 

========================================================== ============================

Example:

 

Source code:

# Include <stdio. h> <br/> # include <stdlib. h> <br/> # include <stdarg. h> <br/> char * <br/> make_message (const char * FMT ,...) <br/>{< br/> int N, size = 100; <br/> char * Buff; // Save the String cache <br/> va_list AP; // typedef char * va_list <br/> If (buff = (char *) malloc (size) = NULL) <br/> return NULL; <br/> while (1) {<br/> // print the application in the requested space <br/> va_start (AP, FMT ); <br/> N = vsnprintf (buff, size, FMT, AP); <br/> va_end (AP); <br/> // If vsnprintf is successfully called, returns the string <br/> If (n>-1 & n <size) <br/> return Buff; <br/> // apply for the original 2x size cache <br/> size * = 2; <br/> If (buff = (char *) realloc (buff, size) = NULL) <br/> return NULL; <br/>}< br/> int <br/> main (void) <br/>{< br/> char * format = "% d, % d"; <br/> char * STR = make_message (format, 5, 6, 7, 8); <br/> printf ("% s/n", STR); <br/> return 0; <br/>}< br/>

Running result:

[Work] $ gcc-w-O stdarg. c

[Work] $./stdarg

5, 6, 7, 8

 

========================================================== ============================

 

Reference extension:

Use and principles of va_start va_arg va_end

 

Va_start exploration and consideration

 

========================================================== ============================

Va_start
Va_end
Usage and principles


1:When you cannot list the types and quantities of all real parameters passing Functions,Parameter table specified by ellipsis
Void Foo (...);
Void Foo (parm_list ,...);

2:How function parameters are transmitted
Function parameters are data structures.:Stack access,Stack inbound from right to left. Eg:

First, we will introduce the call method and principle of the variable parameter table:
First, the parameter memory storage format: the parameter is stored in the stack segment of the memory, and the function is executed from the last one to the stack. Therefore, the stack bottom high address and stack Top Low address are as follows:
Void func (int x, float y, char Z );
So, when calling a function, real parametersChar ZFirst stack, then
Float yAnd finallyInt xTherefore, the order in which variables are stored in the memory isX-> Y-> ZTherefore, theoretically, as long as we detect the address of any variable and know the type of other variables, other input variables can always be found through the pointer shift operation.

Below is
<Stdarg. h>Several important macros are defined as follows:
Typedef char * va_list;
Void va_start (va_list AP, prev_param);/* ANSI version */
Type va_arg (va_list AP, type );
Void va_end (va_list AP );
Va_list It is a character pointer, which can be understood as a pointer to the current parameter. The parameter must be obtained through this pointer.
<Step 1> DefineVa_list Type Variable, ( Hypothesis Va_list Type variable is defined AP) ;
<Step 2> Then It should beAPInitialize to point to the first parameter in the variable parameter table. , This is through Va_start The first parameter is AP Itself, the second parameter is a variable next to the variable in front of the variable parameter table. , That is "..." The previous parameter;
<Step 3> Then Get parameters, callVa_argIts first parameter isAP, The second parameter is the specified type of the parameter to be obtained, then return the value of this specified type, andAPPoint to the next variable location in the variable parameter table;
<Step 4> After obtaining all the parameters, we need AP The pointer is turned off to avoid danger. The method is to call Va_end , Which is the input parameter AP Set Null To close the pointer after obtaining the parameter table.
For exampleInt max (int n ,...);The function should be implemented as follows:

# Include
<Iostream>
Void fun (int ,...)
{
Int * temp = &;
Temp ++;
For (INT I = 0; I <A; ++ I)
{
Cout <* temp <Endl;
Temp ++;
}
}

Int
Main ()
{
Int A = 1;
Int B = 2;
Int c = 3;
Int d = 4;
Fun (4, A, B, C, D );
System ("pause ");
Return 0;
}
Output ::
1
2
3
4

3:Obtain the parameter specified by the ellipsis
Declare one in the function bodyVa_listAnd then useVa_startFunction to obtain the parameters in the parameter list.Va_end ()End. Like this sectionCode:
Void testfun (char * pszdest, int destlen, const char * pszformat ,...)
{
Va_list ARGs;
Va_start (ARGs, pszformat );//Be sure"..."The previous Parameter
_ Vsnprintf (pszdest, destlen, pszformat, argS );
Va_end (ARGs );
}

4. va_start Points argp to the first optional parameter. va_arg returns the current parameter in the parameter list and Points argp to the parameter the next parameter in the list. va_end clears the argp pointer to null . The function can traverse these parameters multiple times, but they must all start with va_start , and end with va_end .

1 ). demonstrate how to use a function with variable parameters, ANSI standard format
# include stdio. h
# include string. h
# include stdarg. h
/* the function prototype Declaration requires at least one definite parameter, note the ellipsis in parentheses */
int demo (char ,...);
void main (void)
{< br> demo ("Demo", "this", "is",
"A", "Demo! "," ");
}< br>/* ANSI standard declaration method, the ellipsis in parentheses indicates the optional parameter */
int demo (char MSG ,...)
{< br>/* defines the structure for saving function parameters */
va_list argp;
int argno = 0;
char para;


/* ArgpPointing to the first optional parameter passed in,MSGIs the final Parameter*/
Va_start (argp, MSG );
While (1)
{
Para = va_arg (argp, char );
If (strcmp (para, "") = 0)
Break;
Printf ("parameter # % d is: % s/n ",
Argno, para );
Argno ++;
}
Va_end (argp );
/*SetArgpSetNull */
Return 0;
}

2 )// Sample Code 1 : Use of variable parameter functions
# Include "stdio. H"
# Include "stdarg. H"
Void simple_va_fun (INT start ,...)
{
Va_list arg_ptr;
Int nargvalue = start;
Int nargcout = 0 ;// Variable Parameter quantity
Va_start (arg_ptr, start );// Start with the fixed parameter address to determine the memory start address of the variable parameter.
Do
{
++ Nargcout;
Printf ("the % d th Arg:
% D/N ", nargcout, nargvalue );// Output parameter values
Nargvalue =
Va_arg (arg_ptr, INT );
// Obtain the value of the next variable parameter.
} While (nargvalue! =
-1 );

Return;
}
Int main (INT argc, char * argv [])
{
Simple_va_fun (100,-1 );
Simple_va_fun (100,200,-1 );
Return 0;
}

3 )// Sample Code 2: Extension -- Implement simple variable parameter functions by yourself.
Below is a simple Printf For more information about the function implementation, see <
C programming language> Examples in
# Include "stdio. H"
# Include "stdlib. H"
Void myprintf (char * FMT ,...)// A simple Printf Implementation, // All parameters must be Int
Type
{
Char *
Parg = NULL;
// Equivalent to the original Va_list
Char C;

Parg = (char *)
& FMT ;// Do not write P = FMT !! This is because // The address of the parameter, not the value.
Parg + =
Sizeof (FMT );// Equivalent to the originalVa_start

Do
{
C = * FMT;
If (C! = '% ')
{

Putchar (C );
//Output character as is
}
Else
{
// Output data by format characters
Switch (* ++ FMT)
{
Case 'D ':

Printf ("% d", * (int *) parg ));


Break;
Case 'X ':

Printf ("% # X", * (int *) parg ));

Break;
Default:

Break;
}
Parg + =
Sizeof (INT );
//Equivalent to the originalVa_arg
}
++ FMT;
} While (* FMT! = '/0 ');
Parg =
NULL;
// Equivalent Va_end
Return;
}
Int main (INT argc, char * argv [])
{
Int I = 1234;
Int J = 5678;

Myprintf ("the first test: I = % d/N", I, j );
Myprintf ("The secend test: I = % d;
% X; j = % d;/N ", I, 0 xabcd, J );
System ("pause ");
Return 0;
}

Int max (int n ,...){
// Parameters N It indicates the number of variable parameters that follow and is used for demarcation. Do not make a mistake when entering
Va_list AP;
// Define Va_list Pointer to access the parameter table
Va_start (AP, N );
// InitializationAPTo point to the first variable parameter,NParameters
Int maximum =-0x7fffffff;
// This is the smallest integer.
Int temp;
For (INT I = 0; I <n; I ++ ){
Temp = va_arg (AP, INT );
// ObtainIntParameters, andAPPoint to the next Parameter
If (maximum <temp) Maximum = temp;
}
Va_end (AP );
// Aftercare, close AP
Return Max;
}
// Test in Main Function Max Function Behavior (C ++ Format)
Int main (){
Cout <max (3, 10, 20, 30) <Endl;
Cout <max (6, 20, 40, 10, 50, 30, 40) <Endl;
}
Now we can see that this method has two very serious vulnerabilities: First, The type of the input parameter is random. So that the parameter can easily obtain a value of an incorrect type. ( For example, enter Float , Int Type to get him ) In this way, the running results will be inexplicably displayed. Second, Changing the parameter table size cannot be obtained at runtime. In this way, there is a possibility of cross-border access, resulting in serious consequences Runtime error .

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.