考虑到有符号整数和无符号整数使用相同的寄存器等,只是以不同的方式解释位模式,而C字符基本上只是8位整数,那么C中有符号字符和无符号字符之间有什么区别? 我知道char的有符号性是实现定义的,但我简单地无法理解它如何可能有所不同,至少当char用于保存字符串而不是执行数学运算时。
考虑到有符号整数和无符号整数使用相同的寄存器等,只是以不同的方式解释位模式,而C字符基本上只是8位整数,那么C中有符号字符和无符号字符之间有什么区别? 我知道char的有符号性是实现定义的,但我简单地无法理解它如何可能有所不同,至少当char用于保存字符串而不是执行数学运算时。
对于字符串来说不会有什么影响。但是在C语言中,当使用char进行数学计算时,它会产生影响。
实际上,在受限内存的环境下工作,比如嵌入式的8位应用程序中,char经常被用于做数学计算,这时它就非常重要了。这是因为在C语言中默认没有byte类型。
uint8_t
类型。除非系统完全不透明,否则字节是8位。 - Lundin就它们所代表的值而言:
0..255(00000000..11111111)
值在低端溢出时为:
0 - 1 = 255(00000000 - 00000001 = 11111111)
值在高端溢出时为:
255 + 1 = 0(11111111 + 00000001 = 00000000)
按位右移运算符(>>
)进行逻辑移位:
10000000 >> 1 = 01000000(128/2 = 64)
-128..127(10000000..01111111)
值在低端溢出时为:
-128 - 1 = 127(10000000 - 00000001 = 01111111)
值在高端溢出时为:
127 + 1 = -128(01111111 + 00000001 = 10000000)
按位右移运算符(>>
)进行算术移位:
10000000 >> 1 = 11000000(-128/2 = -64)
我包括二进制表示法以显示值包裹行为是纯净、一致的二进制算术,与char是有符号/无符号无关(除了右移)。
更新
在评论中提到的一些特定于实现的行为:
#include <stdio.h>
int main(int argc, char** argv)
{
char a = 'A';
char b = 0xFF;
signed char sa = 'A';
signed char sb = 0xFF;
unsigned char ua = 'A';
unsigned char ub = 0xFF;
printf("a > b: %s\n", a > b ? "true" : "false");
printf("sa > sb: %s\n", sa > sb ? "true" : "false");
printf("ua > ub: %s\n", ua > ub ? "true" : "false");
return 0;
}
[root]# ./a.out
a > b: true
sa > sb: true
ua > ub: false
在排序字符串时这很重要。
有几个区别。最重要的是,如果您通过分配太大或太小的整数来溢出char的有效范围,并且char为带符号的,则结果值是实现定义的,甚至可能会引发一些信号(在C中),就像所有带符号的类型一样。相比之下,当您将某些东西分配给无符号字符时,它的大小超出了范围:该值会环绕,您将获得明确定义的语义。例如,将-1分配给无符号字符,您将获得UCHAR_MAX。因此,每当您拥有一个字节,例如从0到2 ^ CHAR_BIT的数字,您应该真正使用无符号字符来存储它。
当传递给vararg函数时,符号也会有所不同:
char c = getSomeCharacter(); // returns 0..255
printf("%d\n", c);
在计算机图形学中(其中通常使用8位值存储颜色),字节的算术运算非常重要。除此之外,我能想到两种主要情况需要考虑字符符号:
讨厌的是,如果所有字符串数据都是7位,则不会出现这些问题。然而,如果您尝试使C/C++程序具备8位清洁性,则这将是一个无休止的晦涩错误源。
char a = (char)42;
char b = (char)120;
char c = a + b;
根据 char 的符号,c 可能是两个值中的一个。如果 char 是无符号的,则 c 将为 (char)162。如果它们是有符号的,则会出现溢出情况,因为有符号 char 的最大值为 128。我猜测大多数实现只会返回 (char)-32。