我发现将uint64_t值右移64位或更多时看起来异常的结果。我希望以下代码输出值0,但它不会 - 它输出值>> 2 - 但只能输出g ++。
#include <iostream>
#include <cstdint>
using namespace std;
int main(void)
{
uint64_t value = 0x5d4d629e80d5489UL;
int shift = 66;
cout << hex << (value >> shift) << endl;
return 0;
}
我编译并运行:
$ g++ -std=c++0x mad.cpp
$ ./a.out
175358a7a035522
$ uname -a
Linux svr 3.2.0-26-generic #41-Ubuntu SMP Thu Jun 14 17:49:24 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
$ g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
我在另一个使用g ++(Debian 4.4.5-8)4.4.5的Linux机器上获得相同的行为。但是,当我使用Visual Studio C ++(Express Edition)编译时,我没有得到相同的行为 - 我得到了我原先预期的结果 - 即0。
我想知道,当x和y是序数并且y大于x中的位数时,假设C ++中的x&gt;&gt; y应该产生0应该是安全的。这是一个g ++错误 - 还是Visual C ++在这里不符合?我假设这不是/不应该是未定义的行为?这可能是CPU特定的吗?
我意识到我总是可以明确地检查每个超过8 * sizeof(值)的班次 - 但是这引入了一个我希望在一些性能关键代码中避免的分支。
这是一个已知问题 - 如果是这样,为了实现一致的跨平台评估,建议的策略是什么?
答案 0 :(得分:9)
关于移位运算符的C ++标准:
如果右操作数,则行为未定义 是...大于或等于提升左操作数的位数。
答案 1 :(得分:1)
此行为未定义 考虑一些关于如何通过太多位变换的信息,以及如何保护自己免受它的影响:INT34-C. Do not shift a negative number of bits or more bits than exist in the operand
答案 2 :(得分:0)
未定义行为的一个原因是它依赖于底层硬件,后者以不同方式实现移位。
在原始的8086上,按照每个位置使用一个时钟滴答,执行了要求的次数。很快就发现这导致了保证的中断响应时间, lousy 。
因此从286开始,硬件屏蔽移位计数并仅使用低位。这就是当66变为2位置时你所看到的。