1
short x = -123;
unsigned short y = -123;

printf("%x\n", x>>3);
printf("%x\n", y>>3);

The result was

fffffff0
1ff0

I don't understand the first result because short is 2 bytes but the result was 4 bytes.

Pang
  • 9,564
  • 146
  • 81
  • 122
alkanian
  • 11
  • 1

3 Answers3

1

The %x format specifier expects an unsigned int argument. Passing any other type of argument (even int) causes undefined behaviour.

You could modify your code to:

printf("%x\n", (unsigned int)(x>>3));
printf("%x\n", (unsigned int)(y>>3));

For x >> 3, first of all x undergoes integer promotion. This turns (short)-123 into (int)-123 because promotions are value-preserving.

Then -123 >> 3 causes implementation-defined behaviour. Probably your implementation defines it as an arithmetic right shift on the 2's complement representation in 32-bit integers:

-123:         11111111111111111111111110000101
-123 >> 3: 11111111111111111111111111110000

which is -16 in 2's complement.

Finally, (unsigned int)-16 is defined as meaning UINT_MAX - 15. 0xFFFFFFFF - 15 gives 0xFFFFFFF0.


For the unsigned short y = -123; line, -123 is converted to unsigned short, giving value for y on your system of USHRT_MAX - 122 which is 65413. Then for y >> 3, this value is promoted to int, retaining the value 65413. The definition of right-shift for positive numbers is to divide by 2 that many times. 65413/8 gives 8176 which is 1FF0 in hex.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Thank you. but the definition of right-shit for positive numbers and negative numbers are different? Because -123/8=-15.375 but the result was -16, not -15. Is it different for negative number? – alkanian Feb 24 '17 at 12:18
  • @alkanian I cover this in my answer; right-shift of negative numbers is *implementation-defined* which means your compiler must choose and document a behaviour. Right-shift of positive numbers is defined as repeated integer division by 2. – M.M Feb 24 '17 at 12:27
  • Okay, what I want to know is in case of arithmetic right shift, negative numbers round down to floor? like -15.375->-16 – alkanian Feb 24 '17 at 13:34
  • @alkanian you need to read your compiler's documentation to find out. Normally the behaviour is as I described in my answer, in terms of bits and not values – M.M Feb 25 '17 at 00:00
1

I don't understand the first result because short is 2 bytes but the result was 4 bytes.

First of all, the >> operator causes implicit integer promotion of both operands to int, unless they weren't already of a larger type. The resulting type of the expression is that of the promoted left operand.

Even without the shift operator, all small integer types that are passed to variable-argument functions such as printf, undergo a similar form of implicit integer promotion (the default argument promotion rule) to int.

This is the reasons why you get 4 bytes.

As for why the values are printed in the way they are, see the answer by M.M. Your code is using the incorrect format specifiers and relies on various forms of poorly-specified behavior, so anything can happen.

Lundin
  • 195,001
  • 40
  • 254
  • 396
-2

Not specifying a modifier for your format in printf indicate you want the default int to be printed ( regardless of the length of the value you are passing ).

you can refer to this printf reference , especially the specifier list to indicate to printf what is the length you desire. In your case you wanted a "%hx" format.

dvhh
  • 4,724
  • 27
  • 33