30

以下代码如何工作以及变量的含义是什么:

y = (x << shift) | (x >> (sizeof(x)*CHAR_BIT - shift));

我在一篇循环班次文章中找到,但没有解释它是如何工作的。

4

4 回答 4

31

这是一种进行循环移位的方法。假设x是 8 位。

+----+----+----+----+----+----+----+----+
| x1 x2 x3 x4 x5 x6 x7 x8 |
+----+----+----+----+----+----+----+----+

然后,将其左移 3 得到:

+----+----+----+----+----+----+----+----+
| x4 x5 x6 x7 x8 0 0 0 |
+----+----+----+----+----+----+----+----+

现在,与in bitsCHAR_BIT*sizeof(x)的宽度相同,为8。所以向右移动 by给我们:xx8 - 3

+----+----+----+----+----+----+----+----+
| 0 0 0 0 0 x1 x2 x3 |
+----+----+----+----+----+----+----+----+

并采取 OR 你得到:

+----+----+----+----+----+----+----+----+
| x4 x5 x6 x7 x8 x1 x2 x3 |
+----+----+----+----+----+----+----+----+

这在技术上是不可移植的,因为移动等于类型宽度的量是不可移植的——所以如果 shift 是 8,那么左移是错误的,如果 shift 是 0,那么右移是错的。但是,这实际上适用于按类型宽度移动时的所有三种常见行为。(实际上,移位量会减少一些模 - 类型的位宽或更大的数字。)

它被称为循环移位或“旋转”,因为在左侧移出的位在右侧移回。

复杂的编译器实际上会将代码编译为硬件旋转指令。

于 2012-11-08T12:56:48.637 回答
25

CHAR_BIT是每字节的位数,应始终为 8。

shift是您想要以循环方式向左移动的位数,因此向左移出的位会在右侧返回。

     1110 0000 << 2 results in:
     1000 0011

示例代码:

   y = (x << 2) | (x >> (8 - 2));
于 2012-11-08T12:52:48.123 回答
7
(x << shift) 

将其向左“移位”位数,返回移出的位

(x >> (sizeof(x)*CHAR_BIT - shift));

为容纳这些位腾出空间

CHAR_BIT是 char 中的位数,所以大多数是 8。在 C 中,您不是一次处理一位,而是至少处理 char 位数。这就是你得到的粒度。

一般来说,

对于一个字符,当你进行位旋转时,你会在一个 8 位字段(1 个字节)上进行

对于 int,当您进行旋转时,您将在 32 位字段(4 字节)上进行


8位示例:

x = 11010101
shift = 2

x << (shift) = 01010100 //shifted left by 2 bits

= x >> ((1 * CHAR_BIT) - shift)
= x >> (6) 
= 00000011 //shifted right by 6bits

OR这些按位给予

01010100 //x << 2
00000011 //x >> 6
________
01010111

即循环移位 2 位的值

于 2012-11-08T12:54:59.967 回答
2

这仅适用于无符号类型。在有符号负数的情况下,最左边的位将被右移运算符(“>>”)的最高有效位(带 1-s)的值替换

我会这样写:

y = (x << shift) | ( (x >> (sizeof(x)*CHAR_BIT - shift)) & (0x7F >> (sizeof(x)*CHAR_BIT - shift) );

在“|”之前 运算符我们确实确认前 n 位( n = sizeof(x)*CHAR_BIT - shift)被归零。我们还假设 x 很短(2 字节长)。所以,它也依赖于类型。

于 2012-11-08T14:27:09.440 回答