问题
The printf
family of functions provide a series of length modifiers, two of them being hh
(denoting a signed char
or unsigned char
argument promoted to int
) and h
(denoting a signed short
or unsigned short
argument promoted to int
). Historically, these length modifiers have only been introduced to create symmetry with the length modifiers of scanf
and are rarely used for printf
.
Here is an excerpt of ISO 9899:2011 §7.21.6.1 “The fprintf function” ¶7:
7 The length modifiers and their meanings are:
hh
Specifies that a followingd
,i
,o
,u
,x
, orX
conversion specifier applies to asigned char
orunsigned char
argument (the argument will have been promoted according to the integer promotions, but its value shall be converted tosigned char
orunsigned char
before printing); or that a followingn
conversion specifier applies to a pointer to a signed char argument.
h
Specifies that a followingd
,i
,o
,u
,x
, orX
conversion specifier applies to ashort int
orunsigned short int
argument (the argument will have been promoted according to the integer promotions, but its value shall be converted toshort int
orunsigned short int
before printing); or that a followingn
conversion specifier applies to a pointer to a shortint
argument....
Ignoring the case of the n
conversion specifier, what do these almost identical paragraphs say about the behaviour of h
and hh
?
- In this answer, it is claimed that passing an argument that is outside the range of a
signed char
,signed short
,unsigned char
, orunsigned short
resp. for a conversion specification with anh
orhh
length modifier resp. is undefined behaviour, as the argument wasn't converted from typechar
,short
, etc. resp. before. - I claim that the function operates in a well-defined manner for every value of type
int
and thatprintf
behaves as if the parameter was converted tochar
,short
, etc. resp. before conversion. - One could also claim that invoking the function with an argument that was not of the corresponding type before default argument promotion is undefined behaviour, but this seems abstruse.
Which of these three interpretations of §7.21.6.1¶7 (if at all) is correct?
回答1:
The standard specifies:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
[C2011 7.21.6.1/9]
What is meant by "the correct type", is conceivably open to interpretation, but the most plausible interpretation to me is the type that the conversion specification "applies to" as specified earlier in the same section, and as quoted, in part, in the question. I take the parenthetical comments about argument promotion to be acknowledging the ordinary argument-passing rules, and avoiding any implication of these functions being special cases. I do not take the parenthetic comments as relevant to determining the "correct type" of the argument.
What actually happens if you pass an argument of wider type than is correct for the conversion specification is a different question. I am inclined to believe that the C system is unlikely to be implemented by anybody such that it makes a difference whether a printf()
argument is actually a char
, or whether it is an int
whose value is in the range of char
. I assert, however, that it is valid behavior for the compiler to check argument type correspondence with the format, and to reject the program if there is a mismatch (because the required behavior in such a case is explicitly undefined).
On the other hand, I could certainly imagine printf()
implementations that actually misbehave (print garbage, corrupt memory, eat your lunch) if the value of an argument is outside the range implied by the corresponding conversion specifier. This also is permissible on account of the behavior being undefined.
来源:https://stackoverflow.com/questions/32529239/is-it-illegal-to-use-the-h-or-hh-length-modifiers-when-the-corresponding-argumen