Number of variable C Parameters

Source: Internet
Author: User
Number of variable C Parameters

There is an uncertain length parameter in C language, such :"... ", Which is mainly used in functions with uncertain number of parameters. The most common example is the printf function.
Prototype:
Int printf (const char * Format [, argument]… );
Example:
Printf ("Enjoy yourself everyday! /N ");
Printf ("the value is % d! /N ", value );
This variable parameter can be said to be a difficult part to understand in the C language. Here there are several problems that will lead to some analysis on it.
Note: In C ++, function overload can be used to differentiate calls of different function parameters, but it still cannot represent any number of function parameters.
Problem: Implementation of printf
How can I implement the printf function and solve the Variable Parameter Problem? Answer and analysis:
A header file <stdarg. h> is defined in the Standard C language to deal with the variable parameter list. It contains a set of macros and a va_list typedef declaration. A typical implementation is as follows:
Typedef char * va_list;
# Define va_start (list) List = (char *) & va_alist
# Define va_end (list)
# Define va_arg (list, mode )/
(Mode *) (List + = sizeof (mode) [-1]
Implement printf by yourself:
# Include <stdarg. h>
Int printf (char * format ,...)
{
Va_list AP;
Va_start (AP, format );
Int n = vprintf (format, AP );
Va_end (AP );
Return N;
}
Problem: parameters are determined only during running.
Is there a way to write a function. The specific form of this function parameter can be determined at runtime?
Answer and analysis:
Currently, there is no "regular" solution, but there is a single eccentric, because there is a function that has set an example for us in this regard, that is, main (), its prototype is:
Int main (INT argc, char * argv []);
The function parameters are argc and argv.
Think deeply, "You can only determine the parameter format at runtime", that is, you cannot see the accepted parameters from the Declaration, that is, the parameters do not have a fixed form at all. A common method is to define a void * type parameter, use it to point to the actual parameter area, and then explain the meaning of the parameters as needed in the function. This is the meaning of argv in the main function, and argc is used to indicate the actual number of parameters, which provides further convenience for our use. Of course, this parameter is not required.
Although the parameters do not have a fixed form, we must parse the meaning of the parameters in the function. Therefore, we naturally have a requirement that the format of the content in the parameter zone should be between the caller and the called, size, effectiveness, and other aspects to reach an agreement, otherwise it will be miserable to talk about each other.
Problem: Transmission of variable length parameters
Sometimes, you need to write a function and pass its variable length parameter directly to another function. Can this requirement be implemented?
Answer and analysis:
At present, you have no way to do this directly, but we can make a detour. First, we define the parameter of the called function as the va_list type, at the same time, the variable length parameter list is converted to va_list in the call function, so that variable length parameters can be passed. See the following:
Void subfunc (char * FMT, va_list argp)
{
...
Arg = va_arg (FMT, argp);/* obtain the desired parameters one by one from argp */
...
}
Void mainfunc (char * FMT ,...)
{
Va_list argp;
Va_start (argp, FMT);/* convert the variable length parameter to va_list */
Subfunc (FMT, argp);/* pass va_list to the subfunction */
Va_end (argp );
...
}
Problem: The variable length parameter type is a function pointer.
I want to use va_arg to extract the variable length parameter with the type of function pointer, but the result is always incorrect. Why?
Answer and analysis:
This is related to the implementation of va_arg. A simple and demo version of va_arg is implemented as follows:
# Define va_arg (argp, type )/
(* (Type *) (argp) + = sizeof (type)-sizeof (type )))
The argp type is char *.
If you want to use va_arg to extract parameters of the function pointer type from the variable parameter list, for example
INT (*) (), then va_arg (argp, INT (*) () is extended:
(* (INT (*) () *) (argp) + = sizeof (INT (*) ()-sizeof (INT (*)())))
Obviously, (INT (*) () *) is meaningless.
To solve this problem, define the function pointer as an independent data type using typedef, for example:
Typedef int (* funcptr )();
At this time, calling va_arg (argp, funcptr) will be extended:
(* (Funcptr *) (argp) + = sizeof (funcptr)-sizeof (funcptr )))
In this way, you can pass the compilation check.
Problem: Get variable length parameters
There is a function with variable length parameters. The following code is used to obtain real parameters of the float type:
Va_arg (argp, float );
Can this be done?
Answer and analysis:
No. In variable length parameters, the "widening" principle is applied. That is, the float type is extended to double; char and short are extended to int. Therefore, if you want to go to the variable length parameter list for the original float type parameters, you need to use va_arg (argp, double ). Va_arg (argp, INT) is used for char and short types ).
Problem: A restriction for defining variable length parameters
Why does my compiler not allow me to define the following functions, that is, variable length parameters, but there is no fixed parameter?
Int F (...)
{
...
}
Answer and analysis:
No. This is required by ansi c. You must define at least one fixed parameter.
This parameter will be passed to va_start (), and then the va_arg () and va_end () will be used to determine the type and value of the variable length parameter for all actual calls.

Some functions in C use variable parameters, such as the common int printf (const char * format ,...), The first parameter format is fixed, and the number and type of other parameters are not fixed.
The C language uses macros such as va_start to process these variable parameters. These macros seem complicated. In fact, the principle is quite simple, that is, according to the characteristics of the parameter stack, the addresses of each variable parameter are obtained starting from the fixed parameter closest to the first variable parameter. Next we will analyze these macros.
In the stdarg. h header file, there are different macro definitions for different platforms. We select the macro definition under the x86 Platform:
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)
_ Intsizeof (n) macro is used to consider the systems whose memory addresses need to be aligned. The macro name should be aligned with sizeof (INT. Generally, sizeof (INT) = 4, that is, the address of the parameter in the memory is a multiple of 4. For example, if sizeof (n) is between 1 and 4, _ intsizeof (n) = 4; If sizeof (n) is between 5 and 8, _ intsizeof (n) = 8.
To obtain each variable parameter from a fixed parameter in sequence, va_start and va_arg make full use of the following two points:
1. When using C language for function calling, first press the last parameter to the stack
2. The memory allocation sequence on the X86 platform is from high-address memory to low-address memory.
High address
Nth Variable Parameter
...
Second Variable Parameter
The first variable parameter? AP
Fixed parameter? V
Low-end address
It can be seen that V is the address of a fixed parameter in the memory. After va_start is called, the AP points to the first variable parameter. This macro is used to increase the memory size occupied by V on the memory address of V, so that the address of the first variable parameter is obtained.
Next, we can imagine that if I can determine the type of this variable parameter, then I will know how much memory it occupies, and I will be able to get the address of the next variable parameter.
Let's take a look at va_arg. It first points AP to the next variable parameter, and then deducts the size of the current variable parameter to get the memory address of the current variable parameter. Then, it performs a type conversion and returns its value.
To determine the type of each variable parameter, either the default type or the fixed parameter contains enough information so that the program can determine the type of each variable parameter. For example, in printf, the program analyzes the format string to determine the large type of each variable parameter.
The last macro is simple. va_end makes the AP no longer point to a valid memory address.
After reading these macros, I can't help but feel again that the C language is too flexible and the code can be very concise. Although sometimes it is hard to understand, once I understand it, you will surely applaud it!
In fact, in varargs. the H header file defines the VA series macros implemented by UNIX System V. the H header file defines Macros in the ansi c format. These two macros are incompatible. Generally, we should use va Macros in the ansi c format.

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.