unsigned short int i = 0;
printf("%u\n",~i);
Why does this code return a 32 bit number in the console? It should be 16 bit, since short is 2 bytes.
The output is 4,294,967,295 and it should be 65,535.
unsigned short int i = 0;
printf("%u\n",~i);
Why does this code return a 32 bit number in the console? It should be 16 bit, since short is 2 bytes.
The output is 4,294,967,295 and it should be 65,535.
%u
expects an unsigned int
; if you want to print an unsigned short int
, use %hu
.
EDIT
Lundin is correct that ~i
will be converted to type int
before being passed to printf
. i
is also converted to int
by virtue of being passed to a variadic function. However, printf
will convert the argument back to unsigned short
before printing if the %hu
conversion specifier is used:
7.21.6.1 The fprintf function
...
3 The format shall be a multibyte character sequence, beginning and ending in its initial shift state. The format is composed of zero or more directives: ordinary multibyte characters (not%
), which are copied unchanged to the output stream; and conversion specifications, each of which results in fetching zero or more subsequent arguments, converting them, if applicable, according to the corresponding conversion specifier, and then writing the result to the output stream.
...
7 The length modifiers and their meanings are:
...
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 ashort int
argument.
Emphasis mine.
So, the behavior is not undefined; it would only be undefined if either i
or ~i
were not integral types.
When you pass an argument to printf
and that argument is of integer type shorter than int
, it is implicitly promoted to int
as per K&R argument promotion rules. Thus your printf
-call actually behaves like:
printf("%u\n", (int)~i);
Notice that this is undefined behavior since you told printf
that the argument has an unsigned
type whereas int
is actually a signed type. Convert i
to unsigned short
and then to unsigned
to resolve the undefined behavior and your problem:
printf("%u\n", (unsigned)(unsigned short)~i);
N1570 6.5.3.3 Unary arithmetic operators p4:
The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. ...
Integer type smaller than int
are promoted to int
. If sizeof(unsigned short) == 2
and sizeof(int) == 4
, then resulting type is int
.
And what's more, printf
conversion specifier %u
expects unsigned int
, so representation of int
is interpreted as unsigned int
. You are basically lying to compiler, and this is undefined behaviour.
It's because the arguments to printf()
are put into the stack in words, as there is no way inside printf to know that the argument is short. Also by using %u
format you are merely stating that you are passing an unsigned number.