Use of variable parameters in C language (reproduced)

xiaoxiao2021-03-06  53

Use of variable parameters in C language (reproduced)

Usage of variable parameters in C language

We encounter some variable variable functions in C language programming, such as Printf ()

This function, its definition is like this:

INT Printf (const char * format, ...);

In addition to having a parameter Format fixation, the number and type of the parameters of the back is

Variable, for example, we can have the following different call methods:

Printf ("% d", i);

Printf ("% s", s);

Printf ("THE NUMBER IS% D, String IS:% S", I, S);

How to write variable parameters and how the function compiler of these variable parameters is

Now? This article conducts some discussions on this issue, hoping to have some help to everyone. Will C

Netizens know that these issues do not exist in C , because C has polymorphism. But C is a C

Overcoming, the following techniques can also be used in C programs. Limited to my own level, if there is

Inappropriate, please correct it.

(1) Write a simple variable parameter C function

Let's explore how to write a C function of a simple variable parameter. Write variable parameters

The C function is to be used in the program to the following macros:

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 parameters).

These macros are defined in stdarg.h, so the program for variable parameters should contain this

Header file. Let's write a function of a simple variable parameter, the change function has at least one integer

Parameters, the second parameter is also an integer, which is optional. Function is just the value 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% D / N", I, J);

Return;

}

We can declare our functions in our header:

EXTERN VOID SIMPLE_VA_FUN (INT I, ...);

We can call this in the program:

SIMPLE_VA_FUN (100);

SIMPLE_VA_FUN (100,200);

As can be seen from this function, we should use variable parameters to follow these steps:

1) First define a VA_LIST type variable in the function, here is Arg_Ptr, this change

The amount 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 a variable parameter is a fixed parameter.

3) Then return the variable parameters with VA_ARG and assign the value to the integer J. VA_ARG second

The parameter is the type of parameters you want to return, here is an INT type.

4) Finally, use the VA_END macro to end the acquisition of variable parameters. Then you can make it in the function

Use the second parameter. If the function has multiple variable parameters, call VA_ARG sequentially

Take each parameter.

If we call the following three methods, we are legal, but the result is not the same:

1) Simple_va_fun (100);

The result is: 100 -123456789 (changed value)

2) Simple_va_fun (100,200);

The result is: 100 200

3) Simple_va_fun (100, 200, 300);

The result is: 100 200

We see that the first call has an error, the second call is correct, the third call despite the result

Correct, but the initial design of our function has conflicts. Let's explore these results below

The reasons and variable parameters are processed in the compiler.

(2) Processing of variable parameters in the compiler

We know va_start, va_arg, va_end is defined in stdarg.h,

Due to the difference between the hardware platform 2) The compiler is different, the defined macro is different. The following is an excerpt from the macro definition of the X86 platform in VC (the '/' represents the folded):

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 for some of the system that requires memory. C language letters

The number is to press the stack from the right direction left, and Figure (1) is the distribution position of the function of the function in the stack. I

We see that VA_LIST is defined as a char *, some platforms or operating systems are defined as void *.

Look at the definition of va_start, defined as & V _intsizeof (v), and & V is a fixed parameter in the stack

Address, after we run Va_Start (ap, v), the AP points to the first variable parameter in the heap.

The address of the stack, as shown in the figure:

High address | ----------------------------- |

| Function Return Address |

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

| .......

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

| Nth parameter (first variable parameter) |

| ----------------------------- | <- VA_START after the AP point

| Nth-1 parameter (last fixed parameter) |

Low address | ----------------------------- | <& V

figure 1 )

Then, we use VA_ARG () to acquire the variable parameter value of Type T, and the above example is an example, I

Take a look at the return value of VA_ARG to take the INT type:

J = (* (INT *) ((AP = _INTSIZEOF (int)) -_ tentizeof (int)));

First AP = SIZEOF (int), has pointed to the address of the next parameter. Then return

AP-SIZEOF (int) INT * pointer, this is the address of the first variable parameter in the stack

(Figure 2). Then use * to obtain the content (parameter value) of this address (parameter value) to j.

High address | ----------------------------- |

| Function Return Address |

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

| .......

| ----------------------------- | <- va_arg after the AP

| Nth parameter (first variable parameter) |

| ----------------------------- | <- VA_START after the AP point

| Nth-1 parameter (last fixed parameter) |

Low address | ----------------------------- | <& V

figure 2 )

The last thing to say is the meaning of VA_END macro. The X86 platform is defined as AP = (char *) 0; making the AP no longer

Point to the stack, but the same as NULL. Some direct definitions ((void *) 0), so the compiler is not

The code will be generated for VA_END, such as the GCC's X86 platform in Linux is defined.

Here everyone should pay attention to a question: Since the address of the parameter is used for VA_START macro,

The parameters cannot be declared as register variables or as a function or array type.

About VA_START, VA_ARG, VA_END's description is these, we have to pay attention to

It is different from different operating systems and hardware platforms, but the principle is similar.

(3) Problems that variable parameters should pay attention to in programming

Because va_start, va_arg, va_end, etc., it is very stupid, the type and number of variable parameters are completely controlled by program code in this function, it does not intelligently

Identify the number and type of different parameters.

Some people will ask: So do you really have intelligent identification parameters in Printf? That's because functions

Printf is a type of parameter from a fixed parameter format string, and then calls VA_ARG

Obtain variable parameters. That is, if you want to achieve intelligent identification, you want to pass.

It is achieved by judging in your own program.

There is another problem because the compiler is not strict enough for the prototype check of the function of variable parameters.

Grid, the programming is unfavorable. 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;

}

Variable parameters are char * type, when we forget to call this function with two parameters, it will appear

Core Dump (UNIX) or page illegal errors (Window platform). But may not

Wrong, but the error is difficult to find, which is not conducive to us to write high quality programs.

The compatibility of the VA series macro will be mentioned below.

System v Unix defines va_start to macros with only one parameter:

va_start (VA_LIST ARG_PTR);

And ANSI C is defined as:

VA_START (VA_LIST ARG_PTR, PREV_PARAM);

If we need to define the definition of System V, we should use the varial header.

Macro, ANSI C macro, the macro of System V is incompatible, we usually use ANSI C, so

It is enough to define the ANSI C and facilitate the transplantation of the program.

summary:

The principle of variable parameters is actually very simple, and the VA series is defined by macro definition.

I am related to the stack. When we write a variable function C function, it is advantageous to have a disadvantage.

To do this, we don't need to use variable parameters. If you are in C , we should use C more

The functionality of the variable parameters is achieved to avoid using a C language.

When writing this article, you can have a cold, you have to have her care, and I would like to dedicate this article to her ...

Author: kevintz

转载请注明原文地址:https://www.9cbs.com/read-115456.html

New Post(0)