c/c++ left shift unsigned vs signed

∥☆過路亽.° 提交于 2020-01-01 04:49:28

问题


I have this code.

#include <iostream>

int main()
{
    unsigned long int i = 1U << 31;
    std::cout << i << std::endl;
    unsigned long int uwantsum = 1 << 31;
    std::cout << uwantsum << std::endl;
    return 0;
}

It prints out.

2147483648
18446744071562067968

on Arch Linux 64 bit, gcc, ivy bridge architecture.

The first result makes sense, but I don't understand where the second number came from. 1 represented as a 4byte int signed or unsigned is

00000000000000000000000000000001

When you shift it 31 times to the left, you end up with

10000000000000000000000000000000

no? I know shifting left for positive numbers is essentially 2^k where k is how many times you shift it, assuming it still fits within bounds. Why is it I get such a bizarre number?


回答1:


Presumably you're interested in why this: unsigned long int uwantsum = 1 << 31; produces a "strange" value.

The problem is pretty simple: 1 is a plain int, so the shift is done on a plain int, and only after it's complete is the result converted to unsigned long.

In this case, however, 1<<31 overflows the range of a 32-bit signed int, so the result is undefined1. After conversion to unsigned, the result remains undefined.

That said, in most typical cases, what's likely to happen is that 1<<31 will give a bit pattern of 10000000000000000000000000000000. When viewed as a signed 2's complement2 number, this is -2147483648. Since that's negative, when it's converted to a 64-bit type, it'll be sign extended, so the top 32 bits will be filled with copies of what's in bit 31. That gives: 1111111111111111111111111111111110000000000000000000000000000000 (33 1-bits followed by 31 0-bits).

If we then treat that as an unsigned 64-bit number, we get 18446744071562067968.


  1. §5.8/2:

    The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1×2E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.

  2. In theory, the computer could use 1's complement or signed magnitude for signed numbers--but 2's complement is currently much more common than either of those. If it did use one of those, we'd expect a different final result.



回答2:


The literal 1 with no U is a signed int, so when you shift << 31, you get integer overflow, generating a negative number (under the umbrella of undefined behavior).

Assigning this negative number to an unsigned long causes sign extension, because long has more bits than int, and it translates the negative number into a large positive number by taking its modulus with 264, which is the rule for signed-to-unsigned conversion.




回答3:


It's not "bizarre".

Try printing the number in hex and see if it's any more recognizable:

std::cout << std::hex << i << std::endl;

And always remember to qualify your literals with "U", "L" and/or "LL" as appropriate:

http://en.cppreference.com/w/cpp/language/integer_literal

unsigned long long l1 = 18446744073709550592ull;
unsigned long long l2 = 18'446'744'073'709'550'592llu;
unsigned long long l3 = 1844'6744'0737'0955'0592uLL;
unsigned long long l4 = 184467'440737'0'95505'92LLU;



回答4:


I think it is compiler dependent .
It gives same value
2147483648 2147483648
on my machiene (g++) .
Proof : http://ideone.com/cvYzxN

And if overflow is there , then because uwantsum is unsigned long int and unsigned values are ALWAYS positive , conversion is done from signed to unsigned by using (uwantsum)%2^64 .

Hope this helps !




回答5:


Its in the way you printed it out. using formar specifier %lu should represent a proper long int



来源:https://stackoverflow.com/questions/22904670/c-c-left-shift-unsigned-vs-signed

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!