Three stdarg. h macros: va_start, va_arg, and va_end

Source: Internet
Author: User

In C language programming, we will encounter some functions with variable parameter numbers, such as the printf () function. Its definition is as follows: int printf (const char * format ,...); besides the fixed format parameter, the number and type of parameters are variable. For example, we can call printf ("% d ", i); printf ("% s", s); printf ("the number is % d, string is: % s", I, s ); how can I write the C Functions of variable parameters and how can the function compilers of these variable parameters be implemented? This article will discuss this issue and hope to help you. C ++ netizens know that these problems do not exist in C ++ because C ++ has polymorphism. however, C ++ is a superset of C. The following technologies can also be used in C ++ programs. limited by my own level. please correct me if there are any mistakes in this article. (1) write a simple variable parameter C function. Next we will discuss how to write a simple variable parameter C function. the following macros should be used in the program to write variable parameters: void va_start (va_list arg_ptr, prev_param); type va_arg (va_list arg_ptr, type); void va_end (va_list arg_ptr ); va here is the meaning of variable-argument (variable Parameter. these macros are defined in stdarg. h, so the program that uses variable parameters should contain this header file. next we will write a simple variable parameter function. The function should have at least one integer parameter, and the second parameter is also an integer. Number, which is optional. the function only prints the values of these two parameters. void simple_va_fun (int I ,...) {va_list arg_ptr; int j = 0; va_start (arg_ptr, I); j = va_arg (arg_ptr, int); va_end (arg_ptr ); printf ("% d \ n", I, j); return;} We can declare our function in our header file as follows: extern void simple_va_fun (int I ,...); we can call simple_va_fun (100); simple_va_fun (100,200) in the program as follows: 1) first, define a va_list variable in the function. Here is arg_ptr, which is a pointer to the parameter. 2) then use the va_start macro to initialize the variable arg_ptr. The second parameter of this macro is the first The previous parameter of variable parameters is a fixed parameter. 3) Use va_arg to return variable parameters and assign them to integer j. the second parameter of va_arg is the type of the parameter to be returned, Which is int type. 4) use the va_end macro to end variable parameter acquisition. then you can use the second parameter in the function. if a function has multiple variable parameters, call va_arg to obtain the parameters. if we call the following three methods, they are all legal, but the results are different: 1) simple_va_fun (100); Result: 100-123456789 (changed value) 2) simple_va_fun (100,200); Result: 100 2003) simple_va_fun (100,200,300); Result: 100 200 we can see that the first call has an error, and the second call is correct, the third type of call, despite the correct results, conflicts with the initial design of our function. the following section describes the causes of these results and how variable parameters are processed in the compiler. (2) variable parameters in the Compiler We know that va_start, va_arg, and va_end are in stdarg. h is defined as a macro. Because 1) the hardware platform is different, 2) the compiler is different, so the defined macro is also different. The following uses stdarg in VC ++. the macro definition of the x86 Platform in h is excerpted as follows ('\' indicates a line break): typedef char * va_list; # define _ INTSIZEOF (n) \ (sizeof (n) + sizeof (int)-1 )&~ (Sizeof (int)-1) # define va_start (ap, v) (ap = (va_list) & v + _ INTSIZEOF (v) # define va_arg (ap, t) \ (* (t *) (ap + = _ INTSIZEOF (t)-_ INTSIZEOF (t) # define va_end (ap) (ap = (va_list) 0) definition _ INTSIZEOF (n) is mainly used for some systems that require memory alignment. C functions are pushed from right to left into the stack. Figure (1) shows the distribution position of function parameters in the stack. we can see that va_list is defined as char *, and some platforms or operating systems are defined as void *. let's look at the definition of va_start, which is defined as & v + _ INTSIZEOF (v), while & v is a fixed parameter in the stack address. So after we run va_start (ap, v, ap points to the address of the first variable parameter in the stack, which is: High address | --- ------------------------ | Function return address | ----------------------------- | ....... | --------------------------- | nth parameter (first variable parameter) | --------------------------------- | <-- ap points after va_start | n-1 parameter (last fixed parameter) | low address | --------------------------- | <-- & v figure (1). Then, we use va_arg () to obtain the variable parameter value of type t. The preceding example is int type, let's take a look at the return value of the va_arg int type: j = (* (int *) (ap + = _ INTSIZEOF (int)-_ INTSIZEOF (int ))); first, ap + = sizeof (int) is directed to the address of the next parameter. then return ap-sizeof (in T) int * pointer, which is the address of the first variable parameter in the stack (figure 2 ). then, use * to get the content of this address (parameter value) and assign it to j. high address | --------------------------- | function return address | ------------------------------- | ....... | ----------------------------- | <-- post-va_arg ap pointing | nth parameter (first variable parameter) | --------------------------- | <-- ap pointing after va_start | n-1 parameter (last fixed parameter) | low address | --------------------------- | <-- & v figure (2) the last thing we want to talk about is the va_end macro. The x86 platform is defined as ap = (char *) 0, so that the ap no longer points to the stack, but is the same as NULL. some are directly defined as (void *) 0, so that the compiler will not _ End generates code. For example, gcc is defined in this way on the linux x86 platform. you should pay attention to one problem: Because the address of the parameter is used in the va_start macro, the parameter cannot be declared as a register variable or as a function or array type. this is the description of va_start, va_arg, and va_end. We should note that different operating systems and hardware platforms have different definitions, but their principles are similar. (3) variable parameters should be noted in programming because va_start, va_arg, va_end, and so on are defined as macros, so they seem stupid, the type and number of variable parameters are completely controlled by the program code in this function. It cannot intelligently identify the number and type of different parameters. someone may ask: Isn't Intelligent Recognition parameters implemented in printf? That is because the function printf analyzes the parameter type from the fixed parameter format string, and then calls va_arg to obtain variable parameters. that is to say, if you want to implement Intelligent Identification of variable parameters, you must make judgments in your own programs. another problem is that the compiler does not strictly check the prototype of the Variable Parameter Function, which is detrimental to programming errors. if simple_va_fun () is changed to void simple_va_fun (int I ,...) {va_list arg_ptr; char * s = NULL; va_start (arg_ptr, I); s = va_arg (arg_ptr, char *); va_end (arg_ptr ); printf ("% d % s \ n", I, s); return;} the variable parameter is char *. When we forget to use two parameters to call this function, the core dump (Unix) or page is invalid (Windows platform ). but there may also be no errors, but they are hard to find, which is not conducive to writing high-quality programs. the following describes the compatibility of va macros. system V Unix defines va_start as a macro with only one parameter: va_start (va_list arg_ptr), while ansi c defines va_start (va_list arg_ptr, prev_param ); if we want to use the definition of system V, we should use vararg. the macros defined in the h header file are incompatible with the macros of system V. We generally use ansi c, so the definition of ansi c is enough, it also facilitates program transplantation. summary: The function principle of variable parameters is actually very simple, and the va series are defined by Macro. Implementation is related to the stack. when we write a variable function's C function, it has both advantages and disadvantages. Therefore, we do not need to use variable parameters unless necessary. in C ++, we should use C ++ polymorphism to implement variable parameter functions, and try to avoid using C language.

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.