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

Source: Internet
Author: User

# Include <iostream> <br/> # include <stdarg. h> <br/> const int n = 5; <br/> using namespace STD; <br/> void stdarg (INT A1 ,...) <br/> {va_list argp; <br/> int I; <br/> int ary [N]; <br/> va_start (argp, A1 ); <br/> ary [0] = A1; <br/> for (I = 1; I <n; I ++) <br/> ary [I] = va_arg (argp, INT); <br/> va_end (argp); <br/> for (I = 0; I <N; I ++) <br/> cout <ary [I] <Endl; <br/>}< br/> void main () <br/>{< br/> stdarg (5, 12, 64, 34, 23); <br/>} 

 

I don't need to talk about the running result ..

If you want to learn more, read the following article, hoping to help you!

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 the following methods:

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. To write a variable parameter C function, we need to use the following Macros in the program:

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, 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 it in the program as follows:

Simple_va_fun (100 );

Simple_va_fun (100,200 );

From the implementation of this function, we can see that the following steps should be taken to use variable parameters:

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 parameter of the first variable parameter, which is a fixed parameter.

3) then return the variable parameter with va_arg and assign the value to the integer J. va_arg. The second parameter is the type of the parameter to be returned. Here it is the 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 200

(3) simple_va_fun (100,200,300 );

Result: 100 200

We can see that there is an error in the first call, the second call is correct, and the third call is in conflict with the initial design of our function although the result is correct. the following section describes the causes of these results and how variable parameters are processed in the compiler.

(2) Processing of 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, the AP points to the address of the first variable parameter in the stack ,:

High address

| ----------------------------- |

| Function return address |

| ----------------------------- |

| ...... |

| ----------------------------- |

| Nth parameter (the first variable parameter) |

| ----------------------------- | <-- After va_start, the AP points

| N-1 parameter (the 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 type:

J = (* (int *) (AP + = _ intsizeof (INT)-_ intsizeof (INT )));

First, ap + = sizeof (INT) is directed to the address of the next parameter. then return the int * pointer of AP-sizeof (INT), 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 |

| ----------------------------- |

| ...... |

| ----------------------------- | <-- Va_arg

| Nth parameter (the first variable parameter) |

| ----------------------------- | <-- After va_start, the AP points

| N-1 parameter (the 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 generate code for va_end. 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) Notes for variable parameters in programming

Because va_start, va_arg, and va_end are defined as macros, it seems stupid. the types and numbers 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:

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 * type. If we forget to use two parameters to call this function, a core dump (UNIX) or an invalid page error occurs (window 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 );

Ansi c is defined:

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.

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.