为什么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方言:
- 签署普通字符的地方
- 其中普通字符未签名
哪些应该C89标准化? C89选择既不标准化,因为它会使已经编写的C代码中的大量假设无效 – 标准人称之为已安装的基础 。 所以C89做了K&R做的事情:保留了普通字符实现定义的签名。 如果您需要特定的签名,请限定您的字符。 现代编译器通常允许您选择带有选项的方言(例如gcc的-funsigned-char
)。
如果忽略(un)signed char和plain char之间的区别,可能发生的“可怕”事情是,如果你在不考虑这些细节的情况下进行算术和移位,那么当你不期望它们时,你可能会得到符号扩展或者反之亦然(甚至在换档时不明确的行为)。
还有一些愚蠢的建议,建议始终使用显式签名或无符号限定符声明您的字符。 只要你只使用指向这些限定类型的指针,这就可以工作,但是只要你处理字符串和字符串函数就需要丑陋的转换,所有这些操作都是指向指向不兼容的指针,它是指向不兼容的演员。 这样的代码突然变得沾满了大量难看的骨头。
字符的基本规则是:
- 对字符串使用plain
char
,如果需要将指针传递给使用plainchar
的函数 - 如果你需要做一点比特和转换字节,请使用
unsigned char
- 如果需要较小的有符号值,请使用
signed char
,但如果空间不是问题,请考虑使用int
将signed char
和unsigned char
视为最小的算术,整数类型,就像有signed short
/ unsigned short
,等等,使用int
, long int
, long long int
。 这些类型都是明确的。
另一方面, char
用于一个非常不同的目的:它是I / O的基本类型和与系统的通信。 它不是用于计算,而是用作数据单元。 这就是为什么你会在命令行参数,“字符串”的定义, FILE*
函数和其他读/写类型IO函数中以及严格别名规则的例外中找到使用的字符串的原因。 故意不严格定义此char
类型,以便允许每个实现使用最“自然”的表示。
这只是分离责任的问题。
(确实, char
与布局兼容的是signed char
和unsigned char
,所以你可以显式地将一个转换为另一个并返回。)