C 中的移位操作

Shift operation in C

是否可以像在 C 中的移位操作中移位 1s 那样移位 0s?

像这样

for (i=0; i<32; i++) {
    if (data & 0x01) { 
        data |= (1<<i);
    }
    else { 
        data &=~ (0<<i);
    }
}

我正在检查是否设置了某些位,并根据这些设置将 0s 或 1s 存储在新变量中,将每一位向左移动。

您不移动 01,而是移动位值,无论是 0 还是 1。换句话说,您移动 位位置 ,而不管其中存储的

来自 C11 标准,章节 §6.5.7。 , 移位运算符

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros.

就是这样,在1s的情况下,移位是可见的

就是说,< 而不是 位移运算符(如您的代码中所示),<<是。

<<(不是 <!)不移动一位。它移动了整数。当你说 1<<5 时,它向左移动 0000000000000001 五位(给定一个 16 位值),得到 00000000001000000<<50000000000000000 向左移动五个位置,结果是 0000000000000000(即相同的值)。其他位不是不确定的:你不能移动一个位(我假设你想要像 ??????????1???????????????0????? 这样的东西,但数字不是那样工作的。)

这看起来像是一个典型的 XY 问题。您可能想使用 data 来打开或关闭其他东西?询问 that。 (编辑:正如 Joachim Pileborg 在问题评论中所说的那样。)

好消息是 - 你想多了。

取整数,例如:01011011

左移 1:10110110.

'whole thing'一起移位;零被移入 LSB。在右移的情况下,无符号数再次为零,或为有符号数实现定义:

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

(S6.5.7)

这意味着右移一个有符号数可能会导致算术移位或逻辑移位。


如果你想将 1s 移到低端,而不是 0s,只需使用一个位掩码来表示你移动的位置数。

移位操作是使用CPU寄存器执行的。寄存器由许多位组成(8、16 和 32 是常见的,你似乎有一个 32 CPU),它们组合起来可以解释为十进制值。

在您的示例中,您使用值 1。C 语言允许以多种方式表示值 1,所有这些都会导致 CPU 寄存器的相同内容:

decimal      hexadecimal  binary
1            0x00000001   0b00000000000000000000000000000001
3713883835   0xDD5D5EBB   0b11011101010111010101111010111011

(在所有情况下,前导 0 都可以省略。)

在二进制表示中,指定了所有 CPU 寄存器位值。如您所见,这包括 0 和 1。因此,当您将值 1 放入寄存器并使用 << 运算符执行左移时,整个寄存器的内容将左移一位,并将 0 放入最低有效位。

在您的代码中,分配给数据的值将遵循以下模式:

i = 0,  data = 0x00000000000000000000000000000001
i = 1,  data = 0x00000000000000000000000000000010
i = 2,  data = 0x00000000000000000000000000000100
etc.
i = 30, data = 0x01000000000000000000000000000000
i = 31, data = 0x10000000000000000000000000000000

如果您使用与 1 不同的值进行移位,您当然会得到不同的模式,但它会遵循相同的规则。 IE。所有位都会移位,无论它们是 1 还是 0。

for(i=0;i<32;i++)
{
    data = (165 << i) // 165 = 0xA5 = 0b10100101
}

Produces:
i = 0,  data = 0x00000000000000000000000010100101
i = 1,  data = 0x00000000000000000000000101001010
i = 2,  data = 0x00000000000000000000001010010100
etc.
i = 28, data = 0x10100000000000000000000000000000
i = 29, data = 0x01000000000000000000000000000000
i = 30, data = 0x10000000000000000000000000000000
i = 31, data = 0x00000000000000000000000000000000

注意随着最高有效位移出寄存器,模式如何在最后消失。

相同的规则适用于使用 >> 运算符进行右移,只是位从最高有效位移向最低有效位。

(有些CPU还有Rotate等精彩的位操作指令。)