Error of variable long parameter list and trap--va_arg an unacceptable type implements a variable long parameter list function and uses the macros provided in Stdarg.h (not discussed here Varargs.h).
For example, we want to implement a simple my_printf:
1. It only returns void and does not record the number of characters in the output
2. It only accepts "%d" by the integer output, "%c" by character output, "%" output '% ' itself
As follows:
1 #include < stdarg.h >
2
3 void my_printf (const char * fmt, ...)
4 {
5 va_list AP;
6 Va_start (AP,FMT); /* Initializes the AP with the last parameter type argument
7 for (; * FMT; + + FMT)
8 {
9/* If not the control character * *
if (* fmt!= '% ')
11 {
Putchar (* fmt); /* Direct OUTPUT * *
Continue;
14}
15/* If the control character, view the next character * *
+ + FMT;
if (' ==* ' fmt)/* If it is Terminator * *
18 {
ASSERT (0); * * This is a mistake * *
break;
21}
Switch (* fmt)
23 {
Case '% ':/* 2 consecutive '% ' Output 1 '% ' *
Putchar ('% ');
-Break;
Case ' d ':/* In accordance with INT output * *
28 {
29/* The next parameter is int, take out */
int i = Va_arg (AP, int);
To printf ("%d", I);
32}
The break;
Case ' C ':/* According to the character output * *
35 {
36 * * But the next parameter is char?
37/* Can be taken out like this. */
char c = Va_arg (AP,
Char);
-printf ("%c", c);
40}
a break;
43}
44}
Va_end (AP); /*
Releaseap--
must be. See
RELATED LINKS*/
46}
This is similar to an exercise in the C + + programming language.
--Need to support the "%c" control character
In the C + + programming language-solution, an answer is given (Chinese p65 page).
But
just like the code above, they are
ErrorOf
To put it simply, when we use Va_arg (AP, type) to take out a parameter,
type must never be aThe following types:
——
Char, signed
Char, unsigned
Char
——
Short, unsigned
Short
--signed
Short、
Shortint, signed
Shortint, unsigned
ShortInt
——
float
One simple reason is:
——
The caller will neverTo my_printf
passingThe above types of
actual Parameters。
In C, when you call a function without a prototype declaration:
The caller will
eachParameter execution "default actual parameter
Promotion(Default argument
Promotions)”。
Also, for variable-length argument lists
beyond the last oneYes
formal arguments for type declarationsAfter the
each actual parameter, the above promotion will also be performed.
The promotion work is as follows:
The actual parameters of the--float type are raised to double
Actual parameters for--char, short, and corresponding signed, unsigned types are elevated to int
--If int cannot store the original value, it is promoted to unsigned int
The caller will then
after AscensionThe parameters
passingto the callee.
So, my_printf is
absolutely no way to receiveThe actual parameters of the type above.
The 38 and 39 lines of the above code should read:
int c = Va_arg (AP,
int);
printf ("%c", c);
Similarly, if you need to use short and float, you should do the same:
Short s = (short) Va_arg (AP,
int);
float f = (float) Va_arg (AP,
Double);
This is also why the printf family function does not have a control character for short and float.
Appendix:
This pitfall is not mentioned in the relevant chapters of the C programming language for variable-length parameter lists.
But there are rules that refer to the default actual parameter elevation:
In the absence of a function prototype, both the char and the short type are converted to the int type, and the float type is converted to the double type.
--"C Language Programming" 2nd Edition 2.7 type conversion p36
In other books, there are also references to this rule:
It is clear that if a parameter is not declared, the compiler will have no information to perform a standard type check and conversion on it.
In this case, a char or short will be passed as int, and float will be passed as a double.
These do not have to be the programmer's expectation.
Footnotes: These are the standard improvements that are inherited by the C language.
For arguments represented by ellipses, their actual parameters perform these ascension (if they belong to a type that requires elevation) before passing, passing the promoted value to the related function. --Translator's note
--"C + + programming language" 3rd Edition-Special Edition 7.6 p138
.... The parameters of the float type are automatically converted to the double type, and the parameters of the short or char type are automatically converted to the int type ...
--"C Traps and defects" 4.4 formal parameters, real participation return value p73
Here's a trap to avoid:
The 2nd parameter of the VA_ARG macro cannot be specified as
Char、
ShortOr
floatType.
Because parameters for char and short types are converted to the int type, the parameters of the float type are converted to double types ...
For example, write this
It's definitely not right .Of
c = Va_arg (Ap,char);
Because we cannot pass a char type parameter, if passed, it will be automatically converted to the int type. The formula above should be written:
c = Va_arg (Ap,int);
--"C Traps and defects" p164
2009/05/07 Modified:
The printf function family has a control character "H" for short.
See: http://www.cplusplus.com/reference/clibrary/cstdio/printf/
RELATED links:
--"Variable long parameter list misunderstanding and traps--va_end is necessary?" 》
Http://www.cppblog.com/ownwaterloo/archive/2009/04/21/is_va_end_necessary.html
This work is licensed with the knowledge sharing signature-non-commercial use-sharing 2.5 Chinese mainland license agreement in the same way.
Reprint Please specify:
Article Author-Ownwaterloo
Release date-April 21, 2009
Original link-http://www.cppblog.com/ownwaterloo/archive/2009/04/21/unacceptable_type_in_va_arg.html