1

I converted an integer value to short, but when I printed the hexadecimal result of short, it was shown in 4-bytes, I can't find the reason.

#include <stdio.h>

void main()
{
   int j = 53191;
   short s = (short)j;
   printf("s = %x",s);
}

output: ffffcfc7

Hamza
  • 171
  • 1
  • 10
Hafeez
  • 11
  • 2
  • See https://stackoverflow.com/a/50882761/1607937 - you need to use `%hx` -> Demo: https://godbolt.org/z/3rG6Y9bsT – Den-Jason Oct 25 '21 at 07:44
  • Alos note that `short`s can be 4 bytes long. – Jean-Baptiste Yunès Oct 25 '21 at 07:50
  • 1
    In accordance with @Jean-BaptisteYunès comment, you may want to use the stdint collection of typedefs to make sure that your variables have the value range you are expecting. `int16_t` for a 16Bit signed integer (short), `uint16_t` for an `unsigned short`. – Refugnic Eternium Oct 25 '21 at 08:03
  • If it weren't for [default argument promotions](https://port70.net/~nsz/c/c11/n1570.html#6.5.2.2), you'd be invoking Undefined Behaviour by using `"%x"` (which requires a corresponding `unsigned` value) with a value of type `short`. – pmg Oct 25 '21 at 08:05
  • @ᕮ_ᑐᑌᑎᕮ4 No, this isn't a duplicate of those posts since `%hx` assumes an unsigned parameter. `short` is not unsigned. – Lundin Oct 25 '21 at 08:50

2 Answers2

2

The reason for that is because the %x specifier expects a 32bit integer to be passed (default argument promotion).

The 0xFFFF prior to the number indicates, that your number is, in fact, negative. That's because 53191 is above the 'signed threshold' of short (which is 32k (-32,768 to 32,767)).

Try it again with a value below 32k or use an unsigned short and your result should change accordingly.

Or, alternatively, please refer to the specification of printf and use the h specifier prior to the x. (%hx) instead, which will tell printf to expect a short.

(Thanks to Adrian Mole for reminding me)

Alaa Mahran
  • 663
  • 4
  • 12
Refugnic Eternium
  • 4,089
  • 1
  • 15
  • 24
0

If we assume that int is 4 bytes and short is 2 bytes, then the value 53191 does not fit inside a short. What happens then isn't well-defined:

Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

So it is up to the compiler to handle this situation as it sees fit. A common implementation is to treat the binary representation of the original type as the corresponding 2's complement representation of the new type. In this case 0xCFC7 which gets treated as a short with value -12345.

Next up, %x assumes a parameter of type unsigned int. printf("s = %x",s); is therefore not well-defined either - it's strictly speaking undefined behavior.

In practice, s will get promoted as required by "the default argument promotions" that apply to all variadic functions like printf. That is, from short to int. Then a common non-standard extension is to reinterpret the binary representation of that promoted int as unsigned int. In case this happens, we would observe the sign extension that took place during argument promotion, meaning the value would have changed from 0xCFC7 to 0xFFFFCFC7. But to print an int with %x isn't guaranteed behavior so we shouldn't rely on it or write code such as this.

Lundin
  • 195,001
  • 40
  • 254
  • 396