unsigned char旋转

时间:2011-05-09 01:22:02

标签: c rotation twos-complement unsigned-char

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

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

如果有人能用char示例及其各自的位来解释,我们将不胜感激。非常感谢。

3 个答案:

答案 0 :(得分:3)

signed charcharunsigned char都是整数类型。为简单起见,我假设CHAR_BIT为8,签名类型为2的补码。所以:

  • signed char是-128到+127
  • 的数字
  • unsigned char是一个0到255之间的数字
  • charsigned 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从结尾移动到开始。使用signed char进行位操作可能会产生错误的结果,如果负的有符号值执行逻辑右移,可能会给出正确的结果,但是在非常不寻常的实现上可以做任何事情。

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

答案 1 :(得分:2)

将变量声明为unsigned char告诉编译器将基础位模式视为从0(00000000)到255(11111111)的数字。将其声明为char告诉编译器将two's complement应用于基础位模式,并将其视为从-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

因此,所有这些都是解释的问题,因为在两种情况下都会添加实际位图并且总和的位模式相同。

答案 2 :(得分:1)

unsigned char只是一个8位整数类型,可以取0到255之间的值,而signed char可以取-127到128之间的值。在实际的机器码中没有真正的区别,除了一个:您使用&gt;&gt;对签名类型进行右移(可以是char,short或int)它是作为算术移位执行的,意味着对于负值(其中1为MSB),1移入,而不是0,并且上述代码将不会按预期工作。

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

00110101旋转无符号且签名为10100110。

但是对于前面1的数字,你得到一个算术移位,因此

11010001旋转无符号为00111010 11010001旋转签名是11111010。