Eric
Eric

Reputation: 24984

bit shift for unsigned int, why negative?

Code:

unsigned int i = 1<<31;
printf("%d\n", i);

Why the out put is -2147483648, a negative value?


Updated question:

#include <stdio.h>

int main(int argc, char * argv[]) {
    int i = 1<<31;
    unsigned int j = 1<<31;
    printf("%u, %u\n", i, j);
    printf("%d, %d\n", i, j);

    return 0;
}

The above print:

2147483648, 2147483648
-2147483648, -2147483648

So, does this means, signed int & unsigned int have the same bit values, the difference is how you treat the 31st bit when convert it to a number value?

Upvotes: 2

Views: 1614

Answers (6)

Jens Gustedt
Jens Gustedt

Reputation: 78973

You are not doing the shift operation on an unsigned but on a signed int.

  • 1 is signed.
  • the shift operation then shifts into the sign bit of that signed (assuming that int is 32 bit wide), that is already undefined behavior
  • then you assign whatever the compiler thinks he wants for that value to an unsigned.
  • then you print an unsigned as a signed, again no defined behavior.

Upvotes: 3

rabi shaw
rabi shaw

Reputation: 441

%u is for unsigned int.
%d is for signed int.

in your programs output :

2147483648, 2147483648     (output for unsigned int)
-2147483648, -2147483648   (output for signed int ) 

Upvotes: 2

Gyapti Jain
Gyapti Jain

Reputation: 4106

printf("%d\n", i); invokes UB. i is unsigned int and you try to print it as signed int. Writing 1 << 31 instead of 1U << 31 is undefined too.

Print it as:

printf("%u\n", i);

or

printf("%X\n", i);

About your updated question, it also invokes UB for the very same reasons (If you use '1U' instead of 1, then for the reason that an int is initialized with 1U << 31 which is out of range value. If an unsigned is initialized with out of range value, modular arithmetic come into picture and remainder is assigned. For signed the behavior is undefined.)

Understanding the behavior on your platform
On your platform, int appears to be 4 byte. When you write something like 1 << 31, it converts to bit patters 0x80000000 on your machine.

Now when you try to print this pattern as signed, it prints signed interpretation which is -231 (AKA INT_MIN) in 2s completement system. When you print this as unsigned, you get expected 231 as output.


Learnings
1. Use 1U << 31 instead of 1 << 31
2. Always use correct print specifiers in printf.
3. Pass correct argument types to variadic functions.
4. Be careful when implicit typecast (unsigned -> signed, wider type -> narrow type) takes place. If possible, avoid such castings completely.

Upvotes: 4

thepace
thepace

Reputation: 2221

%d prints the int version of the unsigned int i. Try %u for unsigned int.

printf("%u\n", i);

int main(){
    printf("%d, %u",-1,-1);
    return 0;
}

Output: -1, 4294967295

i.e The way a signed integer is stored and how it gets converted to signed from unsigned or vice-versa will help you. Follow this.

To answer your updated question, its how the system represents them i.e in a 2's complement (as in the above case where -1 =2's complement of 1 = 4294967295.

Upvotes: 5

Mitch Wheat
Mitch Wheat

Reputation: 300759

Use '%u' for unsigned int

 printf("%u\n", i);

.......................................................

Response to updated question: any sequence of bits can be interpreted as a signed or unsigned value.

Upvotes: 4

doptimusprime
doptimusprime

Reputation: 9411

Try

printf("%u\n", i);

By using %d specifier, printf expects argument as int and it typecast to int. So, use %u for unsigned int.

Upvotes: 3

Related Questions