Linux tricks VA series functions.

Source: Internet
Author: User
Tags variadic

VA functions (variable argument function), the number of arguments variable function, also known as variable parameter function. The VA functions provided by the system to programmers are very few in C + + programming. The *printf ()/*scanf () series function, which is used to format a string at input and output, and a exec* () series function that executes an external file in a program (main (int argc, char* argv[) does not count, so that main () is also a variadic function , it is a function of exec* () with special function and meaning after encapsulation, at least there are many similarities in principle at this level. Because of the uncertainty of the number of parameters, the VA function has great flexibility, ease of use, it is tempting for programmers who have not used variadic functions, so how to write their VA functions, the timing of the use of VA functions, the implementation of the compiler and how. The author gives some humble opinions about the VA function.

first, from printf ()

A variadic function is introduced starting with a formatted string function that everyone is familiar with.

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

The parameter format represents how to format a string of instructions, ...

Represents an optional parameter that is passed to the "..." parameter when invoked, depending on the actual situation.

The system provides functions for VPRINTF series formatted strings, which are used by programmers to encapsulate their own I/O functions.

int vprintf/vscanf (const char * format, va_list AP); Format strings from standard input/output
int vfprintf/vfsacanf (FILE * stream, const char * format, va_list AP); From a file stream
int vsprintf/vsscanf (char * s, const char * format, va_list AP); From a string

Example 1: Format to a file stream that can be used for log files

1FILE *logfile;2 intWritelog (Const Char*format, ...)3 {4 va_list arg_ptr;5 va_start (arg_ptr, format);6 intNwrittenbytes =vfprintf (logfile, format, arg_ptr);7 va_end (arg_ptr);8 returnnwrittenbytes;9 }Ten ... .. One //when called, there is no difference from using printf ().  AWritelog ("%04d-%02d-%02d%02d:%02d:%02d%s/%04d logged out.",  -Nyear, Nmonth, Nday, Nhour, Nminute, szUserName, Nuserid);

Similarly, you can format input from a file, or format the string for standard input and output.

In Example 1 above, the Writelog () function can accept input with a variable number of arguments, in essence, its implementation requires vprintf () support. How to really implement your own variadic functions, including controlling each incoming optional parameter.

ii. definition of VA functions and VA macros

C Language Support VA function, as the C language extension--c++ also support VA functions, but in C + + is not recommended, C + + introduced polymorphism can also be used to implement a variable number of functions. However, the overloaded functionality of C + + can only be a limited number of parameters to anticipate. In contrast, the VA function in C can define an infinite number of overloaded functions equivalent to C + +, which is powerless. The advantages of the VA function are in terms of convenience and ease of use, which can make the code more concise. C compiler in order to unify the implementation on different hardware architectures, hardware platforms, and to increase the portability of code, provides a series of macros to shield the different hardware environment differences.

In the ANSI C standard, the VA macros are defined in Stdarg.h, which are: Va_list,va_start (), Va_arg (), Va_end ().

Example 2: The sum of squares of any natural number:

1 intSqsum (intN1, ...)2 {3 va_list arg_ptr;4 intNsqsum =0, n =N1;5 Va_start (Arg_ptr, N1);6  while(N >0)7 {8Nsqsum + = (n *n);9n = va_arg (arg_ptr,int);Ten } One va_end (arg_ptr); A returnnsqsum; - } - //when called the intNsqsum = Sqsum (7,2,7, One, -1);

The prototype declaration format for variadic functions is:

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

The parameters can be divided into two parts: fixed parameter with number determination and optional parameter with variable number. The function requires at least one fixed parameter, the declaration of a fixed argument is the same as a normal function, and an optional parameter is declared with a "..." when the number is indeterminate. A fixed parameter and an optional parameter make up a parameter list of a function.

With this simple example 2 above, let's look at the role of each va_xxx.
Va_list arg_ptr: Defines a pointer to a variable number of parameter lists;

Va_start (Arg_ptr, ArgN): Causes the parameter list pointer arg_ptr to point to the first optional parameter in the function argument list, stating: ArgN is a fixed parameter before the first optional parameter, (or, last fixed argument; ...). Previous parameter), the order of the parameters in the function argument list in memory is consistent with the order in which the function is declared. If there is a declaration of a VA function that is void va_test (char A, char B, char C, ...), then its fixed parameters are a,b,c, the last fixed argument argn C, and therefore Va_start (Arg_ptr, C).

Va_arg (Arg_ptr, type): Returns the parameter in the argument list that is referred to by the pointer arg_ptr, the return type is kind, and the pointer arg_ptr points to the next parameter in the parameter list.

Va_copy (dest, SRC): The DEST,SRC type is va_list,va_copy () used to copy the parameter list pointer, and dest is initialized to SRC.

Va_end (ARG_PTR): Clears the argument list and invalidates the parameter pointer arg_ptr. Description: After the pointer arg_ptr is invalidated, the arg_ptr can be restored by calling Va_start (), Va_copy (). Each time Va_start ()/Va_copy () is called, a corresponding va_end () must be matched. The parameter pointer can be moved back and forth in the parameter list, but must be within va_start (). Va_end ().

third, how the compiler realizes VA

Example 2 calls Sqsum (7, 2, 7, 11,-1) to find the sum of squares of 7, 2, 7, 11, and 1 is the end flag.

Simply put, the implementation of the VA function is the use and control of parameter pointers.

1 Char *  va_list;  // definition of va_list under x86 platform

The fixed parameter part of the function can be obtained directly from the parameter name when the function is defined; For the optional Parameters section, first point the pointer to the first optional parameter, then move the pointer back, and then determine whether all parameters have been obtained based on the comparison to the end flag. Therefore, the end flag in the VA function must be agreed in advance, otherwise the pointer will point to an invalid memory address, resulting in an error.

Here, move the pointer to point to the next parameter, then move the pointer when the offset is how much, there is no specific answer, because there is a memory alignment (alignment) problem, memory alignment with the specific use of the hardware platform is closely related to For example, the well-known 32-bit x86 platform specifies that all variable addresses must be multiples of 4 (sizeof (int) = 4). The VA mechanism uses the macro _intsizeof (n) To solve this problem, and without these macros, the portability of VA cannot be discussed.

First introduces the macro _intsizeof (n), which takes the size of the memory space of a variable, and is the basis of the VA implementation.

 1   #define  _intsizeof (n) ((sizeof (n) +sizeof (int)-1) &~ (sizeof (int)-1) 2   #define  Va_start (ap,v) (AP = (va_list) &v + _intsizeof (v)) //  First optional parameter address  3   #define  Va_arg (ap,t) (* (t *) (AP + = _ Intsizeof (t))-_intsizeof (t)) //  next parameter address                            4   #define  Va_end (AP) (AP = (va_list) 0) //   

The following table is a memory stack condition for the function int TestFunc (int n1, int n2, int n3, ...) parameter when passed. (The C compiler defaults to pass the parameter as __cdecl.) )

The call to the function is int result = TestFunc (A, B, C, D. e); where e is the end flag.

You can clearly see why VA_XXX macros have been written so well.

1. Va_start. To get the address of the first optional parameter, there are three ways we can do it:

A) = &n3 + _intsizeof (n3)
Address of the last fixed parameter + This parameter takes up the size of memory

B) = &n2 + _intsizeof (n3) + _intsizeof (n2)
The address of a fixed parameter in the middle + the sum of the memory size occupied by all fixed parameters after this parameter

C) = &n1 + _intsizeof (n3) + _intsizeof (n2) + _intsizeof (N1)
Address of the first fixed parameter + sum of memory size occupied by all fixed parameters

From the compiler implementation point of view, Method B), method C) In order to find the address, the compiler also need to know how many fixed parameters, and their size, did not decompose the problem to the simplest, so not very clever way, not to adopt; in relative terms, the two values of the operation in method A can be determined entirely. Va_start () is using a) method to accept the last fixed parameter. The result of calling Va_start () always causes the pointer to point to the address of the next parameter and takes it as the first optional parameter. In a function with more than one fixed parameter, when calling Va_start (), if the last fixed argument is not used, the number of optional arguments has increased for the compiler, which brings some unexpected errors to the program. (Of course, if you think you've know everything your pointer, you can use it to do some very good (and efficient) code, but it will greatly reduce the readability of your code. )

Note: Macro Va_start operates on the address of the parameter and requires that the parameter address be valid. Some types with invalid addresses cannot be treated as fixed parameter types. For example: Register type, its address is not a valid memory address value; Arrays 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 body and second job: Returns the current argument and points the parameter pointer to the next parameter.

At first glance the definition of VA_ARG macro is very awkward, if it is broken into two statements, it can be very clear that it completed two responsibilities.

1 #defineVa_arg (Ap,t) (* (t *) (AP + = _intsizeof (t))-_intsizeof (t)))//Next parameter Address2 //the (* (t *) (AP + = _intsizeof (t))-_intsizeof (t)) is disassembled:3 /*pointer ap refers to the address of a parameter down*/4 1. AP + = _intsizeof (t);//Currently, the AP is already pointing to the next parameter.5 /*The AP subtracts the size of the current parameter to get the address of the current parameter, and then forces the type to return its value after the conversion .*/6 2.return* (T *) (AP-_intsizeof (t))

Recalling the format directives such as%d%s of the PRINTF/SCANF series functions, it is not difficult to understand what they are used for-the type of explicit parameter casts.

(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

Reprint: http://www.ibm.com/developerworks/cn/linux/l-va/

Linux tricks VA series functions.

Related Article

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.