In-depth understanding of VA functions in mobile phone Development

Source: Internet
Author: User

This document describes variable parameters.
Function usage, and then analyze its principles, programmers
How to Implement and encapsulate them, and finally possible problems and preventive measures.

Va function (variable argument function
), Variable parameter count function, also known as Variable Parameter Function. C/C ++
Programming, System
Few va functions are provided to programmers. * Printf ()/* scanf
() Series functions, used for formatting during Input and Output
String
; Exec * () series functions, used in the program
Execute external files
(Main (int
Argc, char *
Argv [] is not counted. Rather than using main () as a variable parameter function, it is better to say that it is a function with special functions and meanings after exec * () is encapsulated, at least on the principle level
There are many similarities ). Because of the uncertainty of the number of parameters, the VA function is flexible and easy to use. It is tempting for programmers who have not used variable parameter functions. How to compile your own
Va function, VA function usage time, compilation
How is it implemented. The author will share with me some of his views on VA functions.

I. Starting with printf ()

From formatting characters that everyone is familiar
String functions start to introduce variable parameter functions.

Prototype: int printf (const char * format ,...);

The format parameter indicates how to format string commands ,...

Optional parameter. The parameter passed to "..." during the call is optional and depends on the actual situation.

The system provides vprintf series string formatting functions for programmers to encapsulate their own I/O functions.

Int vprintf/vscanf (const char * format, va_list AP); // formatted string from standard input/output

Int vfprintf/vfsacanf (File * stream, const char * format, va_list AP); // stream from File

Int vsprintf/vsscanf (char * s, const char * format, va_list AP); // from the string

// Example 1: format a file stream for log files.

File * logfile;

Int writelog (const char * format ,...)

{

Va_list arg_ptr;

Va_start (arg_ptr, format );

Int nwrittenbytes = vfprintf (logfile, format, arg_ptr );

Va_end (arg_ptr );

Return nwrittenbytes;

}

...

// There is no difference between the call and the use of printf.

Writelog ("% 04d-% 02d-% 02d % 02d: % 02d: % 02d % S/% 04d logged out .",

Nyear, nmonth, nday, nhour, nminute, szusername, nuserid );

Similarly, you can also format the input from a file or format the standard input and output strings.

In example 1 above, the writelog () function can accept input with a variable number of parameters. In essence, its implementation requires the support of vprintf. How to implement your own variable parameter functions, including controlling each input optional parameter.

 

 

Ii. Va Function Definition and VA macro

C Language
Supports the VA function as an extension of C language-C ++
The VA function is also supported, but is not recommended in C ++. The polymorphism introduced by C ++ can also implement parameters.
A variable number of functions. However, C ++'s overload function can only be a limited number of foreseeable parameters. In comparison, the VA function in C can define an infinite number of overload functions equivalent to C ++. In this regard, C ++ is powerless. The advantages of VA functions are convenience and ease of use, which enables code
More concise. C Compiler
To unify on different hardware
Architecture
Hardware platform implementation, and increased code portability, provides a series of macros to shield the differences caused by different hardware environments.

In ansi c, VA macros are defined in stdarg. H. They include va_list, va_start (), va_arg (), and va_end ().

// Example 2: Calculate the sum of squares of any natural number:

Int sqsum (INT N1 ,...)

{

Va_list arg_ptr;

Int nsqsum = 0, n = N1;

Va_start (arg_ptr, N1 );

While (n> 0)

{

Nsqsum + = (N * n );

N = va_arg (arg_ptr, INT );

}

Va_end (arg_ptr );

Return nsqsum;

}

// Call time

Int nsqsum = sqsum (7, 2, 7, 11,-1 );

The prototype declaration format of variable parameter functions is:

Type
Vafunction (type arg1, type arg2 ,... );

Parameters can be divided into two parts: fixed parameters with fixed numbers and optional parameters with variable numbers. A function requires at least one fixed parameter. The fixed parameter must be declared in the same way as a common function. The number of optional parameters is unknown "... . The fixed parameters and optional parameters are the same as the parameter list of a function.

Let's take a look at the functions of each va_xxx using the simple example 2 above.

Va_list arg_ptr: defines a pointer to a variable number of parameter lists.
;

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 parameters in the function parameter list are in the memory.
The order in is the same as that in 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 specified by the pointer arg_ptr In the parameter list. Return type
Is type, and the pointer arg_ptr points to the next parameter in the parameter list.

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

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

 

Iii. Compiler
How to Implement va

In Example 2, call sqsum (7, 2, 7, 11,-1) to calculate the sum of squares of 7, 2, 7, and 11.-1 indicates the end sign.

Simply put, the implementation of the VA function is
Pointer
.

Typedef char * va_list; // x86
Definition of va_list in the Platform

The fixed parameter section of the function can be obtained directly from the parameter name when the function is defined. For the optional parameter section, first point the pointer to the first optional parameter, and then move the pointer backward, determine whether all parameters have been obtained based on the comparison with the end mark. Therefore, the ending mark in the VA function must be agreed in advance. Otherwise, the pointer will point to the invalid memory.
Address, causing an error.

Here, the moving Pointer Points to the next parameter, so what is the offset when the pointer is moved? There is no specific answer, because the memory alignment problem is involved here, memory alignment and specific hardware used
The platform is closely related. For example, the 32-bit X86 platform is well known to define all the variables.
The address must be a multiple of 4 (sizeof (INT) = 4 ). Macros used in Va Mechanism
_ Intsizeof (n) to solve this problem. Without these macros, VA portability is impossible.

First, we will introduce macro _ intsizeof (n), which is used to determine the size of the memory occupied by the variable, which is the basis for implementing va.

# DEFINE _ intsizeof (N) (sizeof (n) + sizeof (INT)-1 )&~ (Sizeof (INT)-1 ))

# Define va_start (AP, V) (AP = (va_list) & V + _ intsizeof (V) // The first optional parameter address

# Define va_arg (AP, t) (* (T *) (AP + = _ intsizeof (t)-_ intsizeof (t) // The next parameter address

# Define va_end (AP) (AP = (va_list) 0) // set the pointer to invalid

The following table is for the int testfunc (INT N1, int N2, int N3,…) function ,...) Memory stack when parameters are passed
Status. (C Compilation
The default parameter transfer method is _ cdecl .)

The call to this function is int result = testfunc (A, B, C, D. E), where E is the end mark.

  


We can clearly see the reason for writing the va_xxx macro.

1. va_start. To obtain the address of the first optional parameter, we have three methods:

A) = & N3 + _ intsizeof (N3)

// Address of the last fixed parameter + Memory occupied by this parameter

B) = & N2 + _ intsizeof (N3) + _ intsizeof (N2)

// The address of a fixed parameter in the middle + the sum of memory occupied by all fixed parameters after this parameter

C) = & N1 + _ intsizeof (N3) + _ intsizeof (N2) + _ intsizeof (N1)

// The address of the first fixed parameter + the sum of memory occupied by all fixed parameters

From the perspective of compiler implementation, Method B), method C) in order to find the address, the compiler also
You need to know how many fixed parameters and their sizes are there, and do not break down the problem into the simplest ones. Therefore, it is not a very clever way to choose not to adopt them. Relatively speaking, method) the two values calculated in can be completely determined.
Va_start () uses the) method to accept the last fixed parameter. The result of calling va_start () always directs the pointer to the address of the next parameter and uses it as the first optional parameter.
Number. When va_start () is called in a function that contains multiple fixed parameters, if the last fixed parameter is not used, the number of optional parameters has increased for the compiler.
Unexpected errors. (Of course, if you think you have a thorough understanding of the pointer, you can use it to complete some excellent (efficient) code.
However, this greatly reduces the readability of the Code .)

 

Note: Macro
Va_start is a parameter
The parameter address must be valid. Some address types are invalid.
Cannot be treated as a fixed parameter class
Type. For example, register
Type, its address is not a valid memory
Address value; Array
And functions are not allowed. Their length is a problem. Therefore, these types cannot be used as parameters of the VA function.

2. va_arg has two roles: return the current parameter and make the parameter pointer
Point to the next parameter.

The definition of the va_arg macro is awkward. If we split it into two statements, we can clearly see the two responsibilities it has accomplished.


# Define va_arg (AP, t) (* (T *) (AP + = _ intsizeof (t)-_ intsizeof (t) // The next parameter address
// Split (* (T *) (AP + = _ intsizeof (t)-_ intsizeof (t):
/* Pointer AP points to the address of the next parameter */
1. AP + = _ intsizeof (t); // currently, the AP is directed to the next parameter.
/* AP obtains the address of the current parameter after subtracting the size of the current parameter, and then returns its value after forced type conversion */
2. Return * (T *) (ap-_ intsizeof (t ))
 


Recall printf/scanf
Formatting of series functions such as % d % s
Command, we can easily understand their usage-explicit type of mandatory conversion of parameters.

(Note: printf/scanf is not implemented using va_xxx, but the principle is consistent .)

3. va_end is simple, just to void the pointer.

# Define va_end (AP) (AP = (va_list) 0) // x86
Platform

4. conciseness, flexibility, and danger

From the implementation of VA, we can see that the rational use of pointers puts the C Language
The concise and flexible features are presented to the fullest, and you have to admire the power and efficiency of C. It is undeniable that too much free space for programmers will inevitably make the program
Security
Reduced performance. In va, va_arg must be used to traverse all parameters passed to the function in sequence. There are two risks:

1) determine the parameter type. Va_arg is not so flexible as to check the type, because it is forced type conversion, va_arg forcibly converts the content pointed to by the current pointer to the specified type;

2) End mark. If there is no end sign, VA will return the content in the memory in sequence based on the default type until the access to illegal memory and exit with an error. In Example 2, sqsum () is used to calculate the sum of the squares of natural numbers, so I use negative numbers and 0 as the end sign. For example, scanf uses the received carriage return as the ending sign.
"" Is used as the end sign, and the characters in C cannot be imagined.
Code ""
What will happen? It is estimated that the most popular character array or malloc/free at that time.

Allowing Random Access to memory leaves the possibility of attacks to malicious users. After processing a string carefully designed by the cracker, the program will jump to some malicious code areas for execution, so that the cracker can achieve its attack purpose. (Common Exploit attacks) Therefore, you must disable Random Access to the memory and strictly control the access boundary of the memory.

 

V. UNIX
Va statement for System V compatibility

Variable parameters
The function declaration adopts the ANSI standard. The declaration of the UNIX System V compatibility mode is slightly different. It adds two macros.
: Va_alist, va_dcl. And they are not defined in stdarg. h, but in varargs. h. Stdarg. H is ANSI standard; varargs. H is only used to work with previous programs
This feature is compatible and is not recommended in current programming.

Va_alist: It appears in the function header when the function declaration/definition is used to accept the parameter list.

Va_dcl: Specifies the va_alist statement, which does not need to be followed by a semicolon ";"

The va_start definition is also different. Because the system V Variable Parameter Function declaration does not distinguish between fixed parameters and optional parameters, you can directly operate on the parameter list. Therefore, va_start () is simplified to va_start (AP) instead of va_start (AP, V ). AP is a va_list parameter pointer.
.

Function declaration in UNIX System V compatibility mode:

Type
Vafunction (va_alist)

Va_dcl // a semicolon is not required here

{

// The function body is the same as the ANSI standard

} // Example 3: execl implementation (UNIX System V compatibility mode), from sus v2

# Include

# Deprecision maxargs 100

/* Execl (file, arg1, arg2,..., (char *) 0 );*/

Execl (va_alist)

Va_dcl

{

Va_list AP;

Char * file;

Char * ARGs [maxargs];

Int argno = 0;

Va_start (AP );

File = va_arg (AP, char *);

While (ARGs [argno ++] = va_arg (AP, char *))! = (Char *) 0)

;

Va_end (AP );

Return execv (file, argS );

}

Vi. Expansion and consideration

Variable parameters only need to be declared as "...". However, when we accept these parameters, we cannot "...". The key to implementing the VA function is how to obtain the optional parameters in the parameter list, including the parameter values and types.
. All the above implementations are based on the macro definition of va_xxx from stdarg. h. <Thinking> can we achieve va by ourselves with the help of va_xxx ?, The method I think of is assembly.
. In C, we certainly use C's Embedded Assembly for implementation, which should be possible. As for how much, stability, and efficiency can be achieved, it mainly depends on your memory
And pointer control.

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.