Handle the number of function parameters in the C language with pointers
Cybra_shaoxing@163.com
Now we have almost all programs that each program will use two functions -Printf and Scanf. Discover the difference between these two functions and ordinary functions? That is, these two functions can handle unproductive arguments. The C language is a very loose language that even allows the programmer to pass any number of parameters to the function. This feature is very useful in some cases. For example, now we have to compile a function average () for a series of integer averages (), and if you do not need to change the length, you may need to define a series of prototypes:
Int average_1 (int);
INT AVERAGE_2 (int, int);
Int average_3 (int, int, int);
...
Although C overload function can make these functions become the same name, the encoded work will become large, and the program will have no beauty, and this type of function has a variety of functions, how is it defined? ? Now, we use the length of the argument, you can write only one function and you can handle all the situation. The function prototype is as follows:
Int average (int, ...);
Note that the three points in the parameter list are syntax that meets the C language, not what I have omitted. These three points appear at the end of the function form parameter list, indicating that this will then pass any number of arguments to the function. For example, the function scanf declaration is as follows:
INT __CDECL Scanf (const char * format, ...);
Note: __ CDECL declares is the parameter transmission mode because __cdecl is the default, so it can be omitted.
Note that three points must appear at the end of the parameter list, and the front must define at least one form parameter. Now we can call Average (0, 1, 2, 3, 4, 5, -1) through the function; to find the average of 0 to 5 (the last -1 is the end flag, does not participate in the evaluation operation, this It will be said later).
The current problem is that although we successfully declare the function prototype, and also call the function smoothly, how do you accept these parameters in a function? Unfortunately, the C language itself does not provide a mechanism for accepting parameters like a statement, apparently, we cannot accept these parameters with only one omitted number. But we can solve this problem with a pointer (you can solve this problem with embedded compilation, but that is beyond the category of C language). Let's take a look at the mechanism of the C language function to pass the parameters.
The function in the C language is generally transmitted to the function by copying the parameters to a special memory area (called the stack). For example, function call
Scanf ("% D% f% C% C% S% S% S", & I, & fp, & C, & WC, S, WS);
Its parameters are in memory:
address
parameter
......
......
0x0012F308
Format
0x0012F30C
& I
0x0012F310
& fp
0x0012F314
& c
0x0012F318
& WC
0x0012F31C
S
0x0012F320
WS
......
......
(*) Format is a pointer to the string "% D% F% C% C% S% S"
Note: The situation discussed here is only true for the default parameter transmission mode __cdecl, not applicable to __fastcall and __stddcall. Now we are writing the function of __cdecl mode.
And the address of Format we can use & format, so the address of each parameter can be obtained by adding the value of the pointer & format. For example, & C's address is p = (char **) ((char *) & format sizeof (char **) sizeof (int **) sizeof (float **)) / * This style is bored: -) * / And the value of & c is * P. Because the C language does not provide information about the number of parameters, this information must have a programmer to deliver a parameter. "% D% f% c% c% S% S" is to tell SCANF, and there are six types of pointers as parameters after it. The last parameter -1 of the above pair of function average is also used as the end flag.
To be here, there is a problem, we have to mention it, that is, we have encountered an alignment problem. The so-called alignment is to require the address of each variable to be a multiple of SIZEOF (int)) for the intel80x86 machine. Performance on a 32-bit (4-byte) machine can be divided by all variable addresses. In this way, the variable is not necessarily tightly arranged in memory. For example, the following functions: int bag_example (char C, INT I);
If the address of the parameter C is 0x0012F308, the address of i is not 0x0012F309, but is moved to 0x0012F30c. In general, if the address of the parameter Type P1 is & P1, then its subsequent parameters can be plugged in with an offset behind him.
(char *) & p1 (sizeof (type) sizeof (int) -1) / sizeof (int) * Sizeof (int)
get. (Note that when you add, you must first turn the type of & p1 to (char *).)
At the header file
#define _intsizeof (N) ((SizeOf (N) SizeOf (Int) - 1) & ~ (SIZEOF (Int) - 1))
Here, in order to speed up the operation, the function is the same. Now, suppose this macro has been defined, let's implement the average function as an example:
Int average (int N, ...)
{
INT SUM = 0, C = 0;
INT * P = & n;
IF (n <0) returnograph;
While (* p> = 0)
{
SUM = * P;
C ; (char *) p = _intsizeof (int);
}
Return Sum / C;
}
Since this operation has versatility, ANSI C provides three macros to implement this process. This group macro is defined in the header file
TYPE VA_ARG (VA_LIST ARG_PTR, TYPE);
Void va_end (VA_LIST ARG_PTR);
Void va_start (VA_LIST ARG_PTR, PREV_PARAM);
The method of operation is as follows:
First define a variable of a VA_List type, then use the macro VA_START to give him the first value, Prev_Param is replaced by the parameter name before the omitted number. Then use the macro VA_ARG to get the value of the parameter, the type of parameter is specified in Type. Finally, the variable is released with a macro VA_END.
Below is another implementation of the function Average:
Int average (int N, ...)
{
INT SUM = N, count = 1, p;
VA_LIST ARG_PTR;
IF (n <0) returnograph;
VA_Start (arg_ptr, n);
While ((p = va_arg (arg_ptr, int))> = 0)
{
SUM = P;
COUNT ;
}
VA_END (Arg_PTR);
Return Sum / count;
}
Finally, two points will also be described. First, the contents of the above are related to the implementation of the C language, and the implementation of the C language rely on the CPU and operating system, so it does not apply to all computers, and the difference between the machine will be greatly different. In
Note:
1 There is also a parameter transfer method in the C language is called __fastcall mode. This approach is to transmit parameters into the register (because the number of registers is limited, the remaining parameters can only be placed in memory), so transmitting parameters in this way will improve the efficiency of the program.