Spoon <de*****@localhost.comwrites:
Flash Gordon wrote:
>Spoon wrote, On 26/04/07 12:20:
>>CBFalconer wrote:
Spoon wrote:
Does the following code invoke undefined behavior?
>
#include <stdio.h>
int main(void)
{
unsigned short int u = 42;
printf("%u\n", u);
return 0;
}
Yes.
<snip>
>>>>Is it mandatory to add the 'h' length modifier in the format string?
Yes. Add the -O (capital letter) option to the gcc run.
<snip>
>>Aren't short int parameters "widened" to int in variadic function calls?
You are using unsigned short, which could be widened to int (most
probable) or unsigned int, and using the format specifier for an
unsigned int. int and unsigned int are NOT the same thing.
(Hair-splitting ahead) AFAIU, for the value 42, int and unsigned int
are equivalent because both conversions are well-defined.
Conversion has nothing to do with it. Conversion between int and
double is well-defined, but passing a double argument for a "%d"
format invokes undefined behavior. No conversion, other than argument
promotions, occurs for variadic arguments.
It's true that the value 42 is guaranteed to have the same
*representation* in types int and unsigned int. Specifically, C99
6.2.5p9 says:
The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, and the
representation of the same value in each type is the same.
with a footnote:
The same representation and alignment requirements are meant to
imply interchangeability as arguments to functions, return values
from functions, and members of unions.
So you can look carefully through the standard for proof that the code
will work properly whether the argument is promoted to int or to
unsigned int (note that this depends on a footnote, which is
nonnormative). Note that you'll also need to depend on the
implementer getting this right. It's also likely that the argument
will be promoted to int on all the platforms you use, so you'll never
have a chance to test the case where it's promoted to unsigned int,
just in case you missed something.
Or you can write simpler code that doesn't depend on a potentially
shaky line of reasoning.
>There is also the big question of why you do not want to use what
you know is definitely the correct format specifier.
u is, in fact, an uint16_t and I don't know for sure that u is an
unsigned short int. It might be an unsigned int.
So convert it to unsigned int and use "%u".
Incidentally, there's another subtle issue here. The standard's
description of printf() describes the required formats for various
types. It's almost certainly safe to assume that printf() uses the
same mechanisms as a user-written variadic function, so you can safely
assume that argument promotion occurs as you would expect. But the
standard doesn't *quite* come out and say so. (There was a lengthy
discussion of this in comp.std.c a while ago.) I don't think it's
anything to worry about, but it's enough to make me more cautious with
format strings than I absolutely need to be.
--
Keith Thompson (The_Other_Keith)
ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"