1

我对 unsigned char 是什么感到有点困惑。有符号的字符是位形式的字符的表示,对吗?一个示例问题让我们向右旋转 n 位位置,使用此解决方案的无符号字符的位:

unsigned char rotate(unsigned char x, int n) {
    unsigned char temp = x << 8 - n;
    x = x >> n;
    return (x | temp);
}

如果有人可以用 char 示例及其各自的位进行解释,将不胜感激。非常感谢。

4

3 回答 3

3

signed char,char并且unsigned char都是整数类型。为了简单起见,我假设 CHAR_BIT 是 8,而有符号类型是 2 的补码。所以:

  • signed char是从 -128 到 +127 的数字
  • unsigned char是一个从 0 到 255 的数字
  • char是与 相同的范围signed char,或与 相同的范围unsigned char,具体取决于您的 C 实现。

就 C 而言,字符只是char类型范围内的数字(尽管各种字符函数,例如tolower要求在输入的过程中将值强制转换为无符号类型,即使char是有符号的)。

所以signed charunsigned char都是位形式的字符表示对于 0 到 +127 范围内的数字,它们都使用相同的表示形式(只有一种方法可以用二进制表示正数)。对于该范围之外的数字,负数n的有符号表示与n + 256(2 的补码的定义)的无符号表示相同。

此代码使用的原因unsigned char是带有负符号值的右移具有实现定义的结果。带负符号值的左移具有未定义的行为。通常左移的行为与无符号值的行为相同,这是可以的,但右移会在左侧插入值为 1 的位,即所谓的“算术移位”,这不是这里想要的。无符号值总是移入零,正是移入零使此代码可以构建旋转结果的两个部分和/或它们在一起。

因此,假设输入值为 x = 254 ( 11111110),并且 n = 1,我们得到:

x << 7 is 0111111100000000
x >> 1 is         01111111
|      is 0111111101111111
convert to unsigned char to return is 01111111

如果我们使用有符号类型而不是unsigned char,我们很可能会得到:

x is -2                           11111110
x << 7 is 11111111111111111111111100000000 (assuming 32-bit int, since
           smaller types are always promoted to int for arithmetic ops)
x >> 1 is implementation-defined, possibly 
          11111111111111111111111111111111
| is      11111111111111111111111111111111
convert to signed char to return is -1

因此,使用 unsigned char 进行位操作会产生正确的答案,旋转 1 位以将 0 从末尾移动到开头。使用有符号字符进行位操作,可能会给出错误的结果,如果负符号值进行逻辑右移,可能会给出正确的结果,但在真正不寻常的实现中可以做任何事情。

对于像旋转这样的位操作任务,几乎总是要使用无符号类型。它消除了对实现的依赖(除了类型的宽度),并且避免了你必须分别推理负值和非负值。

于 2011-05-09T02:09:36.413 回答
2

将变量声明为unsigned char告诉编译器将底层位模式视为从 0 (00000000) 到 255 (11111111) 的数字。将其声明为char告诉编译器将二进制补码应用于底层位模式并将其视为从 -128 (10000000) 到 127 (01111111) 的数字。

考虑一个 3 位数字。如果它没有签名,你有:

000 = 0
001 = 1
010 = 2
011 = 3
100 = 4
101 = 5
110 = 6
111 = 7

如果已签名,您有:

100 = -4
101 = -3
110 = -2
111 = -1
000 =  0
001 =  1
010 =  2
011 =  3

关于算术(如该链接所述)的简洁之处在于,您不必将有符号二进制数与无符号二进制数区别对待。您只需进行实际的二进制数学运算,而不考虑有符号或无符号。但是您必须将有符号/无符号解释应用于输入和输出。

在已签名的领域中,您可能拥有:

2 + (-3) = 010 + 101 = 111 = -1

但在无符号领域,这是:

2 + 5 = 010 + 101 = 111 = 7

所以这完全是一个解释问题,因为在这两种情况下,添加的实际位模式和总和的位模式是相同的。

于 2011-05-09T01:27:54.127 回答
1

unsigned char 只是一个 8 位整数类型,可以取 0 到 255 之间的值,而有符号 char 可以取 -127 到 128 之间的值。在实际的机器代码中没有真正的区别,除了一个:当你做使用 >> 对有符号类型进行右移(无论是 char、short 还是 int)它是作为算术移位执行的,这意味着对于负值(其 MSB 为 1)移入 1,而不是 0 和上面的代码将无法按预期工作。

编辑:您上面将无符号字符旋转 3 位的有符号和无符号代码示例:

00110101 旋转无符号和有符号是 10100110。

但是对于前面带有 1 的数字,您会得到算术移位,因此

11010001 旋转无符号是 00111010。
11010001 旋转有符号是 11111010。

于 2011-05-09T01:31:27.820 回答