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定义为有符号或无符号,以避免像上述代码那样的危险误用呢?
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定义为有符号或无符号,以避免像上述代码那样的危险误用呢?
主要是因为历史原因.
在大多数上下文中,类型为char
的表达式被提升为int
(因为许多CPU没有8位算术运算).在某些系统上,签名扩展是实现这一点的最有效方式,它主张将纯签名设为char
.
另一方面,EBCDIC字符集包含具有高阶位集的基本字符(即,值为128或更大的字符);在EBCDIC平台上,char
几乎必须是无符号的.
ANSI C Rationale(1989年的标准)在这个问题上没有太多的话要说;第3.1.2.5节说:
指定了三种类型的字符:
signed
、普通和unsigned
.A.
再往前看,1975年的C Reference Manual的早期版本是这样说的:
可以在AN
int
可能在的任何地方使用char
对象.在所有情况下,char
通过将其符号通过上部传播转换为int
结果整数的8位.这与两人的观点是一致的. 同时用于字符和整数的补码表示法. (但是,符号传播功能在其他 实施.)
这一描述比我们在后面的文档中看到的更具体于实现,但它确实承认char
可以是签名的,也可以是未签名的.在"符号传播消失"的"其他实现"上,将char
对象提升到int
将对8位表示进行零扩展,实质上将其视为8位无符号量.(该语言还没有signed
或unsigned
关键字.)
C的直接前身是一种叫做B的语言.B是一种无类型的语言,所以char
的签名或未签名的问题不适用.有关C语言早期历史的更多信息,请参见已故的Dennis Ritchie的home page,现在是moved here.
至于代码中发生了什么(应用现代C规则):
char c = 0xff;
bool b = 0xff == c;
如果纯char
是无符号的,那么c
的初始化将其设置为(char)0xff
,这在第二行中相当于0xff
.但是如果普通char
是有符号的,那么0xff
(int
类型的表达式)将转换为char
——但是由于0xff
超过了CHAR_MAX(假设CHAR_BIT==8
),结果是implementation-defined.在大多数实现中,结果是-1
.在比较0xff == c
中,两个操作数都转换为int
,使其等于0xff == -1
或255 == -1
,这当然是错误的.
另一件需要注意的重要事情是,unsigned char
、signed char
和(普通)char
是三种截然不同的类型.char
与either unsigned char
or signed char
具有相同的表示;它是哪一个由实现定义.(另一方面,signed int
和int
是同一类型的两个名称;unsigned int
是不同的类型.(不同的是,为了增加轻量级,声明为纯int
的位域是有符号的还是无符号的,这是由实现定义的.)
是的,这一切都有点混乱,我相信如果今天从头开始设计C语言,它的定义会有所不同.但是,C语言的每个版本都必须避免 destruct (过多)现有代码,并在较小程度上避免 destruct 现有实现.