对未定义的C++班次操作员行为和换行"pattern space"感到困惑

Confused by undefined C++ shift operator behavior and wrapping "pattern space"

本文关键字:pattern 换行 space C++ 未定义 操作员      更新时间:2023-10-16

我对在不确定的C 行为的文章的"转移运营商"部分中阅读的内容感到困惑。

在手臂架构上,换档操作员总是表现得好像在256位模式空间中发生,无论操作数的大小如何,即重复或"环绕",只有每256个位置。另一种思考方式是,模式移动了指定数量的位置模式256。然后,结果当然包含模式空间最不明显的位。

桌子特别奇怪:

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     |
+-----------------------------------+

这些价值是什么,为什么重要?

轮班运算符不包装。根据C 规范,如果将32位值移动32,结果始终为0。(编辑:我错了,我错了,请参阅答案!)那么这篇文章是什么?什么是未定义的行为?

当我在x86上运行此代码时,我得到0

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

据说此代码段说明了问题:

// 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;
}

我希望返回的值为lo,因为程序员移走了所有hi位。警告很好,因为这可能是一个错误,但是我看不出任何未定义的行为...

如果使用x86或x64机器指令来移动该值,它们将掩盖移位量,仅使用较低的位来进行实际偏移。其他一些硬件可能不会。

这就是为什么它不确定。

在您使用文字1 << 32的示例中,编译器可能会计算值,这就是为什么它是0。尝试在Real X86硬件上进行操作,您将获得1

结果的类型是晋升的左操作数的类型。如果右操作数为负,或大于或等于晋升的左操作数的位中的长度,则行为是不确定的。

这是从C 11的§5.8/1。如果您的INT为32位,则无法移动32(右移或左移动,无论左操作数的签名)。

根据C 规范,如果移动32位的32位值,结果始终为0

不,这不是标准所说的。不确定的行为是将32位类型移动32或更多(5.8/1)

由于不确定的行为是在手臂上移动256位(没有257位或更高的类型),因此CPU完全有权包装。