对于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示例及其各自的位来解释,我们将不胜感激。非常感谢。
答案 0 :(得分: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 char
和unsigned 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。