为什么C或C ++标准没有将char定义为signed或unsigned?

int main() { char c = 0xff; bool b = 0xff == c; // Under most C/C++ compilers' default options, b is FALSE!!! } 

C或C ++标准都没有将char指定为有符号或无符号,它是实现定义的。

为什么C / C ++标准没有明确地将char定义为signed或unsigned,以避免像上面的代码那样危险的错误使用?

历史原因大多。

chartypes的expression式在大多数情况下被提升为int (因为很多CPU没有8位算术运算)。 在某些系统上,签名扩展是最有效的方法,这个方法可以使得简单char被标记。

另一方面,EBCDIC字符集具有设置了高位的基本字符(即,值为128或更大的字符)。 在EBCDIC平台上, char必须是未签名的。

ANSI C理论 (针对1989年的标准)在这个问题上没有太多的说法; 第3.1.2.5节说:

指定了三种types的字符: signed ,plain和unsigned 。 一个普通的char可以表示为有符号的或无符号的,这取决于实施方式,如在先前的实践中那样。 引入typessigned char是为了在实现普通字符为unsigned的系统上提供一个字节的有符号整数types。 出于对称的原因,被signed的关键字被允许作为其他整型的types名称的一部分。

回顾一下,从1975年的C参考手册早期版本说:

一个char对象可能在int任何地方使用。 在所有的情况下,通过在结果整数的高8位传播它的符号, char被转换为int 。 这与用于字符和整数的二进制补码表示是一致的。 (但是,在其他实现中,符号传播function会消失。)

这个描述比我们在后面的文档中看到的更具体的实现,但是它确实承认char可以是有符号的,也可以是无符号的。 在“符号传播消失”的“其他实现”上,将char对象提升为int将对8位表示进行零扩展,本质上将其视为8位无符号数量。 (该语言还没有signed或未unsigned关键字。)

C的前身是一种叫B的语言。B是一种无types的语言,所以char被签名或未签名的问题不适用。 有关C的早期历史的更多信息,请参阅已故丹尼斯·里奇的主页 ,现在移到这里 。

至于你的代码中发生了什么(应用现代的C规则):

 char c = 0xff; bool b = 0xff == c; 

如果plain char是无符号的,那么c的初始化将它设置为(char)0xff ,它等于第二行中的0xff 。 但是,如果使用纯char进行签名,则0xffinttypes的expression式)将转换为char – 但由于0xff超过了CHAR_MAX(假设CHAR_BIT==8 ),因此结果是实现定义的 。 在大多数实现中,结果是-1 。 在比较0xff == c ,两个操作数都转换为int ,使其等于0xff == -1255 == -1 ,这当然是错误的。

另外需要注意的是, unsigned charsigned char和(plain) char是三种不同的types。 charunsigned char signed char具有相同的表示forms; 它是实现定义的。 (另一方面, signed intint是同一types的两个名字; unsigned int是一个不同的types(除了只是添加到轻浮的地方,它是实现定义的,是否声明为int的位域是有符号的或无符号。))

是的,这一切都是一团糟,我相信如果C是从头开始devise的,那么它的定义就会有所不同。 但是,C语言的每一个版本都不得不避免破坏(太多)现有的代码,并且在现有的实现方面的程度较低。

char首先是为了存储字符,所以有符号或无符号并不重要。 真正重要的是如何有效地对char进行math运算。 所以依靠这个系统,编译器会select最合适的

在ARMv4之前,ARM本身不支持加载半字和有符号字节。 要加载一个有符号的字节,你必须对LDRB进行符号扩展(LSL,然后ASR回降)。 这很痛苦,所以char默认是无符号的。

https://stackoverflow.com/a/6532932/995714