Home > Net >  Why does unsigned short (0xffff) print 65,535 and unsigned int (0xffffffff) print -1 in C?
Why does unsigned short (0xffff) print 65,535 and unsigned int (0xffffffff) print -1 in C?

Time:09-22

I think the title explains pretty well what I'm asking so here is my code.

#include <stdio.h>
unsigned short u_short = 0xffff;
unsigned int u_int = 0xffffffff;

int main(){
    
    
    printf("unsigned short = %d\n", u_short);
    printf("unsigned int = %d\n", u_int);
    
    return 0;
}

Here is my printout. printout picture

CodePudding user response:

printf("unsigned int = %d\n", u_int); is undefined behavior (UB) when u_int is out of the positive int range. Do not used "%d" to print unsigned.

Use printf("unsigned int = %u\n", u_int);

CodePudding user response:

This is likely what happened in your C implementation:

  • In printf("unsigned short = %d\n", u_short);, the unsigned short value 65,535 is automatically converted to an int with the same value.1,2

  • The int value 65,535 is passed to printf, which formats it as “65535” due to the %d conversion specification.

  • In printf("unsigned int = %d\n", u_int);, the unsigned int value 4,294,967,295 is passed to printf; it is not converted to an int. As an unsigned int, 4,294,967,295 is represented with 32 one bits.

  • Because of the %d conversion specification, printf seeks an int value that was passed as an argument. For this, it finds the bits passed for your unsigned int, because an unsigned int and an int are passed in the same place in your C implementation, so the printf looking for an int finds the bits in the same place the calling routine put the unsigned int bits.3

  • When interpreted as an int type, these bits, 32 ones, represent the value −1.3 Given the −1 value, printf formats it as “-1” due to the %d conversion specification.

Footnotes

1 In many places in expressions, including arguments corresponding to ... of a function declaration, values of types narrower than int are automatically promoted to int, as part of the integer promotions.

2 A C implementation could have an unsigned short as wide as an int, in which case this conversion would not occur. That is rare these days.

3 This is a description of what likely happened in your C implementation. The behavior is not defined by the C standard and may vary in other C implementations or even in different programs in your C implementation.

CodePudding user response:

printf has some anomalies due to the usual argument promotions. In particular, arguments of type char and short are promoted to int when passing them to printf. Usually this is fine, but sometimes it results in surprises like these. What you get when you promote an unsigned 16-bit 0xffff to 32 bits is not 0xffffffff.

printf has some relatively little-known and relatively rarely-used modifiers to, in effect, undo those promotions and print char and short arguments as what they "really were". So you'll see more-consistent results if you tell printf that you were actually passing a short, like this:

printf("unsigned short = %hd\n", u_short);
printf("unsigned int = %d\n", u_int);

Now printf knows that the argument in the first call was really a short, so it treats it as such. On my machine, this now prints

unsigned short = -1
unsigned int = -1

(Now, with that said, it's arguably a bad idea to print unsigned integers with %d, as the other answers and comments have explained.)

  •  Tags:  
  • c
  • Related