I read through the method for using variadic functions in C at http://www.gnu.org/s/libc/manual/html_node/Argument-Macros.html#Argument-Macros
However, I was unable to grasp the meaning of self-promoting data types. What are开发者_如何学C they & how are they different from non-self-promoting data types?
Here is the C99 standard; "self-promoting" types are those which promote to themselves when the default argument promotions (§6.5.2.2 paragraph 6, referencing the integer promotions described in §6.3.1.1) are applied.
My reading of the va_arg
definition (§7.15.1.1) is that this limitation is implied by the standard. The relevant part is in paragraph 2:
[...] or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions) [...]
which is quite clear about the type of the actual next argument being promoted, but I read as not saying anything about type being promoted. (I think the "(as promoted...)" clause is just a reminder that default argument promotions are performed on the trailing arguments when a varargs function is called.)
This item in the list of undefined behaviour in §J.2 supports this reading:
— The
va_arg
macro is invoked when there is no actual next argument, or with a specified type that is not compatible with the promoted type of the actual next argument, with certain exceptions (7.15.1.1).
(although yes, I know, Annex J is "informative" rather than "normative"...).
In which case: va_arg(ap, float)
(for example) cannot be valid - type in that case is float
, but the promoted type of the actual next argument cannot possibly be float
(a float
argument would be promoted to double
).
This seems to be a glibc restriction, the C standard doesn't have that.
The idea behind this is that integer types that have so-called "conversion rank" smaller than int
are automatically promoted to signed
or unsigned
int
. A va_arg function then finds such a wider argument. The va_arg
macro must then first read the wider argument of type int
, say, and then cast it back to the original type.
(Same holds for float
w.r.t to double
.)
For the unaware programmer this can have surprising result, so I agree with the idea that this should be avoided. The description you are citing seems to imply that it is imposed to not use a small type. This is bogus and as I said not in alignment with the standard. On the other hand if you write code as they suggest you will never have a portability issue with that because this is a restriction and not an extension.
精彩评论