【问题标题】:Circular shift in cc中的循环移位
【发布时间】:2012-11-08 12:48:53
【问题描述】:

以下代码是如何工作的,变量是什么意思:

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

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

【问题讨论】:

    标签: c


    【解决方案1】:

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

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

    然后,将其左移 3 得到:

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

    现在,CHAR_BIT*sizeof(x)x 的宽度相同,单位为 8。因此将 x 向右移动 8 - 3 得到:

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

    然后采用 OR 你得到:

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

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

    之所以称为循环移位或“旋转”,是因为从左侧移出的位会在右侧移回。

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

    【讨论】:

    • +1,但 8 不是一个很好的例子,说明它是未定义的移位量,因为按照通常的算术转换,移位的类型至少是(有符号或无符号)int,并且int 至少为 16 位。
    • 很好的解释,但是我在进行按位左移时遇到了问题。编译器似乎采用 32 位一组的位,但在进行循环左移时我只需要处理 8 位。这意味着1111 0000 向左移动 1 时应该给出1110 0001 而不是编译器现在给出的1111 00000。你能帮忙吗?
    【解决方案2】:

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

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

         1110 0000 << 2 results in:
         1000 0011
    

    示例代码:

       y = (x << 2) | (x >> (8 - 2));
    

    【讨论】:

    • 如果我想用 1111101010 之前的 10 位比特流对数字进行循环移位,那么 CHAR_BIT 是 10 还是我错了?
    • CHAR_BIT 对于您将在 21 世纪使用的任何健全的架构来说始终为 8 :-)
    • @PascalCuoq x &gt;&gt; 8 - 2 被解析为 x &gt;&gt; (8 - 2) 并带有警告:运算符 '>>' 的优先级低于 '-'; '-' 将首先被评估 [-Wshift-op-括号]
    • @fujianjin6471 确实。我已经删除了我的评论,但我会说括号也保留在答案中,看看那些不太熟悉 C 的人会如何感到困惑。
    【解决方案3】:
    (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位的值

    【讨论】:

    • 我有一个问题:当我对 10101 使用
    • @user1809300 这是因为 8 位粒度。 1010100010101。上面的例子并不直接适用于 C。它只是说明了它是如何工作的。在 C/C++ 中,您将一次处理 8 位字符。
    • @user1809300 我不明白。您提供了哪些意见,结果又是什么?
    • 结果是 84 insead of 20
    • @user1809300 x 是?另外,请参见上面的更新示例。我做了8位。以前太混乱了。
    【解决方案4】:

    这仅适用于无符号类型。在有符号负数的情况下,最左边的位将被右移运算符(“>>”)的最高有效位(带 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 字节长)。所以,它也是依赖于类型的。

    【讨论】:

    • 关于无符号类型的好警告!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多