C编程语言(K&R)练习2-8:将数字向右旋转。这样可以吗?

3

我正在跟随《C程序设计语言》(K&R)学习。这是练习2-8。它要求创建一个函数,将数字向右旋转一定数量的位。

我想出来的答案“似乎”可以完成任务,并且只用了两行代码。然而,我在网上查找其他方法时发现这个Stack Overflow答案讲述了逐位移动每个位。如果我像下面的代码一样批量移动,会有什么问题吗?我有什么遗漏的地方吗?

#include <stdio.h>

/* Rotate number 'num' to the right by 'rbits' bits */

int RotRight(unsigned int num, int rbits) {

    unsigned int mask = num << ((sizeof(int)*8)-rbits);
    return (num>>rbits)|mask;
}

为了容纳我从评论中学到的东西,这是上面代码的编辑版本。这看起来不错吗?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int RotRight(int num, int rbits) {

    if(num<0) {
        fprintf(stderr, "Rotating negative numbers is undefined\n");
        exit(EXIT_FAILURE);
    }

    if(rbits >= sizeof(int)*CHAR_BIT)
        rbits = rbits % (sizeof(int)*CHAR_BIT);

    if(rbits <= 0)
        return num; // rbit range should be 0 to (bitwidth - 1)

    unsigned int mask = num << ((sizeof(int)*CHAR_BIT)-rbits);
    return (num>>rbits)|mask;
}

1
我想知道为什么该函数返回的类型与传递的“num”不同。 - Weather Vane
1
在那段代码中还有一个神奇的数字,你可能是指CHAR_BITS(或类似的东西,只需搜索网络)而不是硬编码8位字符,这非常普遍但仍然不能保证。 - Ulrich Eckhardt
1
@Weather Vane “如果右操作数的值为负数或大于等于提升后的左操作数的宽度,则行为未定义。” C11 §6.5.7 3 - chux - Reinstate Monica
2
@Somjit 几十年的经验 Grasshopper. - chux - Reinstate Monica
1
@天气旗帜 注意:早期的8086/8088处理器位移操作码会将0-255范围内的每个位都移出。值大于16对16位寄存器没有功能影响。该指令不能被中断,每1个时钟周期进行一次移位。它成为了最糟糕的情况命令,需要255个时钟周期才能完成。因此,如果在第1个时钟周期发生关键中断,则必须等待250多个时钟周期才能服务该中断-这是一个显着的中断延迟。随后的处理器仅使用32位移位的最低有效5位。 - chux - Reinstate Monica
显示剩余23条评论
1个回答

2

第一版代码不错,但第二版变得过于复杂。建议使用无符号数以简化。

由于代码在旋转位,旋转N次位宽度与旋转0相同。换句话说,我们只需要使用移位计数的最低有效位。

#include <stdio.h>
#include <limits.h>

/* Rotate number 'num' to the right by 'rbits' bits */

unsigned RotRight(unsigned num, unsigned rbits) {
  #define BIT_WIDTH (CHAR_BIT * sizeof num)
  #define RBIT_MASK (BIT_WIDTH - 1)
  rbits %= BIT_WIDTH;  // The compiler is likely to change this to rbits &= RBIT_MASK;
  unsigned mask = num << ((BIT_WIDTH - rbits) % BIT_WIDTH);
  return (num >> rbits) | mask;
}

为什么要写 '// compiler likely to change this to rbits &= RBIT_MASK;' ? - Somjit
1
@Somjit BIT_WIDTH 是一个常量。它很可能是2的幂次方。在这种情况下,rbits %= BIT_WIDTH 等同于 rbits &= RBIT_MASK 而且 &= 是一条快速指令,很可能比 %= 更快。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接