Reputation: 21
the following code:
int main() {
int small_num = 0x12345678;
int largest_num = 0xFFFFFFFF;
printf("small: without casting to short: 0x%.8x, with casting to short: 0x%.8x\n", small_num>>16, (short)(small_num>>16));
printf("large: without casting to short: 0x%.8x, with casting to short: 0x%.8x\n", largest_num>>16, (short)(largest_num>>16));
return 0;
}
gives me the output (using codepad):
small: without casting to short: 0x00001234, with casting to short: 0x00001234
large: without casting to short: 0xffffffff, with casting to short: 0xffffffff
That's seems extremely strange. Anyone have an idea why it happens this way?
Upvotes: 2
Views: 133
Reputation: 4752
The hexadecimal constant has type unsigned int
. When converted to signed int
the value becomes -1
. Right-shifting a negative value usually leaves the sign-bit unchanged, so -1 >> 16
is still -1
. A short int
passed to a variadic function gets promoted to signed int
which, when interpreted as an unsigned int
by the %x
conversion specifier, prints out 0xffffffff
.
However, your code is broken for a number of reasons.
int largest_num = 0xFFFFFFFF;
The type of the hexadecimal constant is the first of the following types in which its value can be represented: int
, unsigned int
, long int
, unsigned long int
, long long int
, unsigned long long int
.
If int
has more than 32 bits, you're fine.
If int
has 32 bits or less, The result is implementation-defined (or an implementation-defined signal is raised).
Usually, largest_num
will have all bits set and have the value -1
.
largest_num>>16
If the value of largest_num
is negative, the resulting value is implementation-defined. Usually, the sign bit is left unchanged so that -1
right-shifted is still -1
.
printf ("0x%.8x\n", (short)(largest_num>>16));
When you pass a short int
to a variadic function, the value will be promoted to int
. A negative value will be preserved when converted to the new type.
However, the "%x"
conversion specifier expects an unsigned int
argument. Because unsigned int
and signed int
are not compatible types, the behaviour of the code is undefined. Usually, the bits of the signed int
is re-interpreted as an unsigned int
, which results in the original value of the hexadecimal constant.
printf(...);
printf()
is a variadic function. Variadic functions (typically) use different calling conventions than ordinary functions. Your code invokes undefined behaviour if you don't have a valid declaration of print()
in scope.
The usual way to provide a declaration for printf()
is to #include <stdio.h>
.
Source: n1570 (the last public draft of the current C standard).
Upvotes: 0
Reputation: 41
When you are casting to (short) in the printf call, then the compiler will cast it from short back to int, which is the parameter which is passed to printf. Therefore, 1234 will be mapped to 1234, and ffff (which is exactly -1) is mapped to ffffffff. Note that negative integers are expanded from short to long by adding "on bits" on their left.
Upvotes: 2