为什么x+0和x0有不同的结果?

为什么 x+0 和 x|0 有不同的结果?

下面是我的代码。

我的环境是 WSL (Debian Sid) + GCC 10.2.1。

#include <stdio.h>

/**
 * Do rotating left shift. Assume 0 <= n < w
 * Examples when x = 0x12345678 and w = 32:
 * n = 4 -> 0x23456781, n = 20 -> 0x67812345
 */
unsigned rotate_left(const unsigned x, const int n)
{
    const int w = sizeof(unsigned) << 3;
    return (x << n) + (x >> (w - n));
}

int main()
{
    int x = 0x12345678;
    printf("n = 4, %#x -> %#xn", x, rotate_left(x, 4));
    printf("n = 20, %#x -> %#xn", x, rotate_left(x, 20));
    printf("n = 0, %#x -> %#xn", x, rotate_left(x, 0));
}

当 n = 0 时,结果为 0x2468acf0。

当我用 替换return (x << n) + (x >> (w - n))return (x << n) | (x >> (w - n)),我得到 0x12345678。

回答

如果x是最多 32 位的整数类型,则x>>32Undefined Behavior,这意味着结果绝对可以是任何东西(并且在不同的程序中可以是不同的东西)。(也适用于x<<32。)[注 1]

从 C 标准的 §6.5.7 第 3 段中,关于<<>>运算符,重点补充说:

如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。

因此,如果n <= 0或,您的旋转功能将不起作用n >= w,您应该测试这些情况而不是假设它们不会发生(因为它们显然会发生)。


笔记

  1. 实际上,在 Intel 硬件(可能还有其他硬件)上,操作数宽度的移位是空操作,而不是“清除为 0”。那么x>>32x,由于是x<<0,这样的总和的两倍x,而按位或正好x。但是你不能依赖这个事实,因为它是Undefined Behavior,编译器优化可能会导致其他任意结果。
  • @内森;`sizeof(unsigned)` 可能是 4,在这种情况下 `sizeof(unsigned)&lt;&lt;3`,也就是 **代码实际所说的**,是 32。

以上是为什么x+0和x0有不同的结果?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>