为什么带变量的左移和带常量的左移会产生不同的结果?
why does left shift with variables generate different result from that with constant?
在编译了下面的代码之后,我得到了一个奇怪的结果,a =1而b =0。有人能解释一下幕后发生了什么吗?
#include<iostream>
using namespace std;
int main(){
int n=32;
int a=1<<n; //turns out a=1
int b=1<<32; //turns out b=0
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
标准没有定义,或者更确切地说,它将其定义为"未定义的行为",当左移超过整数类型的大小时会发生什么。[这种未定义行为的原因是不同的硬件可能会或可能不会表现相同,例如,向左移动32位]。
在第一种情况下[至少没有优化],编译器生成指令来计算1 << 32
-在x86上变成1 << (32 & 31)
,与1 << 0
相同-因此你得到1。
在第二种情况下,编译器将自己计算该值,这将变成溢出,并给出0。
很有可能(但不确定),如果您更改编译器选项来优化代码,它在两种情况下都给出零。如果你要做一个小位移的循环,你会得到你想要的行为(尽管你可能会发现"有趣"的行为与数字变成负的事实,所以最好对所有的移位操作使用无符号,真的)。
因为您正在调用未定义的行为。移动比类型中存在的更多的位没有定义为具有任何特定的行为。
见http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html?m=1
超大移位量:将uint32_t移位32位或更多未定义的。我猜这是因为潜在的不同cpu上的移位操作对这个:for做不同的事情例如,X86将32位的移位量截断为5位(因此移位由32位与移位0位相同,但PowerPC会截断32位移位等于6位(因此移位32位产生零)。由于这些硬件的差异,行为完全不同未定义(因此在PowerPC上移动32位可以格式化您的硬盘驱动器,它是不是保证产生零)。的成本消除这种未定义的行为是编译器必须要做的为变量移位触发一个额外的操作(如'and'),其中将使它们在普通cpu上的成本增加一倍。
- 使用boost::multiprecision cpp_int左移时出现超时错误
- 警告:左移计数 >= 在 C++ 中将字节流读取为双精度变量时的类型宽度
- 左移<<如何在不同的功能中给出不同的结果?
- 使用 AVX2 指令左移 128 位数字
- <<(按位左移)在 Swift 中的数组上做什么?
- 带有左移操作员C 的意外输出
- 编译器将输出的流运算符<<解释为用于按位左移的二进制运算符<<
- 左移负整数为零是否有意义?
- 在 VS 移位中,UINT64 上的左移(64 >移位> 32)位仅 32 位
- C++20 是否为"overflow"的有符号整数很好地定义了左移?
- C++左移操作
- 为什么编译器左移 0
- 左col结果分配给相同的矩阵会导致分割故障
- 如何在位明智的操作中选择正确的左移
- 为什么很多人使用左移<<而不是乘法
- 左移 0 有什么意义
- 虽然左移运算符 (<<) 在 std::cout 之前使用,但它有什么用?
- 左移<<有些意外的行为
- 使用左移运算符将 F 转换为 FF
- 为什么带变量的左移和带常量的左移会产生不同的结果?