为什么char与signed char或unsigned char不兼容?

我发现C99标准有一个语句,它拒绝类型char和signed char / unsigned char类型之间的兼容性。

C99标准注35:

在limits.h中定义的CHAR_MIN将具有值0或SCHAR_MIN之一,这可用于区分这两个选项。 无论做出何种选择,char都是与其他两种类型不同的类型,并且与两者都不兼容。

我的问题是为什么委员会否认兼容性? 理由是什么? 如果char与signed char或unsigned char兼容,那么会发生什么可怕的事吗?

根源在编译器历史中。 八十年代基本上有两种C方言:

  1. 签署普通字符的地方
  2. 其中普通字符未签名

哪些应该C89标准化? C89选择既不标准化,因为它会使已经编写的C代码中的大量假设无效 – 标准人称之为已安装的基础 。 所以C89做了K&R做的事情:保留了普通字符实现定义的签名。 如果您需要特定的签名,请限定您的字符。 现代编译器通常允许您选择带有选项的方言(例如gcc的-funsigned-char )。

如果忽略(un)signed char和plain char之间的区别,可能发生的“可怕”事情是,如果你在不考虑这些细节的情况下进行算术和移位,那么当你不期望它们时,你可能会得到符号扩展或者反之亦然(甚至在换档时不明确的行为)。

还有一些愚蠢的建议,建议始终使用显式签名或无符号限定符声明您的字符。 只要你只使用指向这些限定类型的指针,这就可以工作,但是只要你处理字符串和字符串函数就需要丑陋的转换,所有这些操作都是指向指向不兼容的指针,它是指向不兼容的演员。 这样的代码突然变得沾满了大量难看的骨头。

字符的基本规则是:

  • 对字符串使用plain char ,如果需要将指针传递给使用plain char的函数
  • 如果你需要做一点比特和转换字节,请使用unsigned char
  • 如果需要较小的有符号值,请使用signed char ,但如果空间不是问题,请考虑使用int

signed charunsigned char视为最小的算术,整数类型,就像有signed short / unsigned short ,等等,使用intlong intlong long int 。 这些类型都是明确的。

另一方面, char用于一个非常不同的目的:它是I / O的基本类型和与系统的通信。 它不是用于计算,而是用作数据单元。 这就是为什么你会在命令行参数,“字符串”的定义, FILE*函数和其他读/写类型IO函数中以及严格别名规则的例外中找到使用的字符串的原因。 故意不严格定义此char类型,以便允许每个实现使用最“自然”的表示。

这只是分离责任的问题。

(确实, char布局兼容的是signed charunsigned char ,所以你可以显式地将一个转换为另一个并返回。)