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位无符号量.(该语言还没有signedunsigned关键字.)

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 == -1255 == -1,这当然是错误的.

另一件需要注意的重要事情是,unsigned charsigned char和(普通)char是三种截然不同的类型.chareither unsigned char or signed char具有相同的表示;它是哪一个由实现定义.(另一方面,signed intint是同一类型的两个名称;unsigned int是不同的类型.(不同的是,为了增加轻量级,声明为纯int的位域是有符号的还是无符号的,这是由实现定义的.)

是的,这一切都有点混乱,我相信如果今天从头开始设计C语言,它的定义会有所不同.但是,C语言的每个版本都必须避免 destruct (过多)现有代码,并在较小程度上避免 destruct 现有实现.

C++相关问答推荐

Ebpf内核代码:permission denied:invalid access to map value

在#include中使用C宏变量

在函数中使用复合文字来初始化C语言中的变量

ZED for SDL上的C语言服务器

如何在C中通过套接字自定义数据类型读取原始变量?

为什么该函数不将参数值保存到数据 struct 中?

如何将常量char*复制到char数组

C在声明带有值的数组时,声明大小有用吗?

在移动数组元素时获得意外输出

如果格式字符串的内存与printf的一个参数共享,会发生什么情况?

如何在不更改格式说明符的情况下同时支持双精度和长双精度?

意外的C并集结果

按字典顺序打印具有给定字符的所有可能字符串

在C中使用字符串时是否不需要内存分配?

我错误地修复了一个错误,想了解原因

C Makefile - 如何避免重复提及文件名

在 C 中传递参数时出现整数溢出

我该如何处理这个 C 90 代码中的内存泄漏?

CS50多项,印刷优胜者

在 C 中有效返回多个值