算术右移给出虚假结果?
我一定是疯了,但是我机器上的 gcc 4.7.3
给出了最荒谬的结果.这是我正在测试的确切代码:
I must be absolutely crazy here, but gcc 4.7.3
on my machine is giving the most absurd result. Here is the exact code that I'm testing:
#include <iostream>
using namespace std;
int main(){
unsigned int b = 100000;
cout << (b>>b) << endl;
b = b >> b;
cout << b << endl;
b >>= b;
cout << b << endl;
return 0;
}
现在,任何自行右移的数字都应该导致 0 (n/(2^n) == 0
与 整数除法、n>1
和 positive/unsigned),但不知何故这是我的输出:
Now, any number that's right shifted by itself should result in 0 (n/(2^n) == 0
with integer divide, n>1
, and positive/unsigned), but somehow here is my output:
100000
100000
100000
我疯了吗?可能会发生什么?
Am I crazy? What could possibly be going on?
推荐答案
在 C++ 中与在 C 中一样,移位仅限于移位值的大小(以位为单位).例如,如果 unsigned int 是 32 位,那么超过 31 位的移位是未定义的.
In C++ as in C, shifts are limited to the size (in bits) of the value shifted. For instance, if unsigned int is 32 bits, then a shift of more than 31 is undefined.
在实践中,一个常见的结果是使用移位量的最低5位,忽略高位;这是因为编译器生成了一条完全符合此要求的机器指令(例如 x86 上的 SHR).
In practice, a common result is that the 5 least-significant bits of the shift amount are used and the higher order bits are ignored; this is due to the compiler producing a machine instruction which does exactly that (eg SHR on x86).
在这种情况下,移位值是 100000
(十进制),恰好是二进制的 11000011010100000
- 低 5 位为零.所以,你实际上得到了一个 0 的转变.但是你不应该依赖这个;从技术上讲,您看到的是未定义行为.
In this case, the shift value is 100000
(decimal) which happens to be 11000011010100000
in binary - the lower 5 bits are zero. So, you're effectively getting a shift by 0. You shouldn't rely on this however; technically, what you're seeing is undefined behaviour.
参考文献:
对于 C,N1570 6.5 节.7:
For C, N1570 section 6.5.7:
如果右操作数的值为负或大于或等于提升的左操作数的宽度,行为是未定义.
If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
对于 C++,N3690第 5.8 节[expr.shift]":
For C++, N3690 section 5.8 "[expr.shift]":
如果右操作数为负数或更大,则行为未定义大于或等于提升的左操作数的位长度.
The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
N1570 是一个草案,与已发布的 ISO C11 标准几乎相同;该条款自 1989 年 ANSI C 标准以来几乎相同.
N1570 is a draft, nearly identical to the released ISO C11 standard; this clause has been pretty much the same since the 1989 ANSI C standard.
N3690 是 C++ 标准的最新草案;我不确定它是否是最好用的,但同样,这个条款没有改变.
N3690 is a recent draft of the C++ standard; I'm not sure whether it's the best one to use, but again, this clause hasn't changed.
相关文章