简体   繁体   English

对未定义的C ++移位操作符行为和包装“模式空间”感到困惑

[英]Confused by undefined C++ shift operator behavior and wrapping “pattern space”

I'm confused by something I read in the Shift Operators section of an article on undefined C++ behavior . 我对在未定义的C ++行为文章的Shift Operators部分中读到的内容感到困惑。

On the ARM architecture, the shift operators always behave as if they take place in a 256-bit pattern space, regardless of the operand size--that is, the pattern repeats, or "wraps around", only every 256 positions. 在ARM体系结构中,移位运算符总是表现得好像它们发生在256位模式空间中,而不管操作数大小 - 即模式重复或“环绕”,只有每256个位置。 Another way of thinking of this is that the pattern is shifted the specified number of positions modulo 256. Then, of course, the result contains just the least-significant bits of the pattern space. 另一种思考方式是将模式移动指定数量的位置模256.然后,当然,结果仅包含模式空间的最低有效位。

The tables are especially strange: 表格特别奇怪:

Given a 32-bit integer with a value of 1:
+-----------------------------------+
| Shift left    ARM    x86    x64   |
+-----------------------------------+
| 32            0      1      1     |
| 48            0      32768  32768 |
| 64            0      1      1     |
+-----------------------------------+

What are these values, and why do they matter? 这些价值是什么,为什么它们重要?

The shift operators don't wrap. 换班操作员不会换行。 According to the C++ specification if you shift a 32-bit value left by 32, the result is always 0. (EDIT: I'm wrong, see the answers!) So what is this article getting at? 根据C ++规范,如果你将32位值移到32位,结果总是为0. (编辑:我错了,看看答案!)那么这篇文章是什么? What is the undefined behavior? 什么是未定义的行为?

When I run this code on x86 I get 0 : 当我在x86上运行此代码时,我得到0

printf("%d", 1 << 32);

Supposedly this code snippet illustrates the problem: 据说这段代码片段说明了这个问题:

// C4293.cpp
// compile with: /c /W1
unsigned __int64 combine (unsigned lo, unsigned hi) {

    return (hi << 32) | lo;   // C4293

    // try the following line instead
    // return ( (unsigned __int64)hi << 32) | lo;
}

I would expect the returned value to be lo , since the programmer shifted away all the hi bits. 我希望返回的值是lo ,因为程序员将所有的hi位移开。 A warning is nice, since this was probably a mistake, but I don't see any undefined behavior... 警告很好,因为这可能是一个错误,但我没有看到任何未定义的行为......

If you use the x86 or x64 machine instructions for shifting the value, they will mask off the shift amount and only use the lower bits for the actual shift. 如果使用x86或x64机器指令来移动值,它们将屏蔽移位量并仅使用较低位进行实际移位。 Some other hardware might not do that. 其他一些硬件可能不会这样做。

That's why it is undefined. 这就是它未定义的原因。

In your example with literals 1 << 32 , it is likely that the compiler computes the value and that's why it is 0 . 在您的文字1 << 32的示例中,编译器可能会计算该值,这就是它为0的原因。 Trying the operation on real x86 hardware, you would get 1 . 尝试在真正的x86硬件上运行,你会得到1

The type of the result is that of the promoted left operand. 结果的类型是提升的左操作数的类型。 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. 如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义。

This is from §5.8/1 from C++11. 这是来自C ++ 11的§5.8/ 1。 If your ints are 32bit, you can't shift by 32 (right- or left-shift, regardless of the signedness of the left operand). 如果你的整数是32位,你不能移动32(右移或左移,不管左操作数的符号)。

According to the C++ specification if you shift a 32-bit value left by 32, the result is always 0 根据C ++规范,如果将32位值左移32,则结果始终为0

No, that's not what the standard says. 不,这不是标准所说的。 It is undefined behavior to shift a 32-bit type by 32 or more (5.8/1) 将32位类型移位32或更多(5.8 / 1)是未定义的行为

Since it is undefined behavior to shift by 256 bits on ARM (which has no 257-bit-or-greater type), the CPU is perfectly entitled to wrap at that point. 由于在ARM(没有257位或更大类型)上移位256位是未定义的行为,因此CPU完全有权在此时换行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM