【问题标题】:Why is char not compatible with signed char or unsigned char?为什么 char 与 signed char 或 unsigned char 不兼容?
【发布时间】:2012-09-27 23:34:18
【问题描述】:

我发现 C99 标准中有一个声明否认 char 类型和有符号字符/无符号字符类型之间的兼容性。

C99 标准注释 35:

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

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

【问题讨论】:

  • 问题是,如果char 与您机器上的其中一个兼容,那么它将与其他一些系统上的另一个兼容。这一切都取决于底层硬件。委员会决定将其制成三种不同的类型作为折衷方案。
  • @Vaughn Cato 相关但不一样。我不明白兼容性的含义。
  • @BoPersson 你的评论真的很有帮助。我对兼容性的含义不是很清楚。你能解释一下什么是兼容的以及提出这个概念的原因吗?对于基本类型,是否兼容等于相同?
  • @junwanghe - 一个普通的 char 具有与 either signed charunsigned char 相同的表示和值。出于效率原因,C 使用底层硬件提供的任何内容。这意味着char 在不同的计算机上会略有不同。已选择将 char 类型设为三种不同的类型,即使其中两种在其他方面完全相同(但并非所有系统上的两种类型都相同)。对于其他类型,如intsigned intint 是同一类型,只是char 比较特殊。

标签: c char compatibility


【解决方案1】:

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

  1. 普通字符的签名位置
  2. 普通字符是无符号的

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

如果您忽略 (un)signed char 和 plain char 之间的区别,可能发生的“可怕”事情是,如果您在不考虑这些细节的情况下进行算术和移位,您可能会在不考虑这些细节的情况下得到符号扩展期待它们,反之亦然(甚至在转换时出现未定义的行为)。

还有一些愚蠢的建议,建议始终使用明确的有符号或无符号限定符声明您的字符。只要您仅使用指向此类限定类型的指针,此方法就可以工作,但是一旦您处理字符串和字符串函数,它需要丑陋的强制转换,所有这些都在pointer-to-plain-char 上运行,它在没有强制转换的情况下是赋值不兼容的。这样的代码突然被大量丑陋的石膏所覆盖。

字符的基本规则是:

  • 对字符串使用纯 char,如果您需要将指针传递给采用纯字符的函数
  • 如果您需要对字节进行位旋转和移位,请使用 unsigned char
  • 如果您需要较小的有符号值,请使用 signed char,但如果空间不是问题,请考虑使用 int

【讨论】:

  • 我知道为什么会有三种角色类型以及它们不同的职责。但是在某个实现中,char 被定义为与有符号字符或无符号字符具有相同的范围、表示和行为。现在范围、表示和行为都相同了,为什么 char 与有符号字符/无符号字符不兼容?兼容性是什么意思?
  • 发生在我身上(并把我带到这里)的“可怕的事情”是我不知道为什么我的代码在与 char 参数一起使用时既不使用有符号字符的模板代码,也没有使用无符号字符的模板代码...
  • 有许多简单的方法可以改进标准。一个明显的问题是要求实现选择并记录char 的四种处理方法之一:作为signed char 的别名,作为unsigned char 的别名,作为与signed char 不兼容的签名类型,或者作为与unsigned char 不兼容的无符号类型。在许多系统上,前两种选择比后两种更容易实现,而且我看不出禁止它们有什么用处。
【解决方案2】:

signed charunsigned char 视为最小的算术、整数类型,就像signed short/unsigned short,等等intlong intlong long int。这些类型都已明确指定。

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

这只是分离职责的问题。

(不过,char 确实与signed charunsigned char布局兼容,因此您可以显式地将一个转换为另一个并返回。)

【讨论】:

  • 你可以看到 char 有点像 byte 没有任何与之关联的整数类型。
  • @SergeyL.:嗯,根据定义char 是最小的可寻址单元,所以它确实是你所说的“字节”。请记住,它的位数不是固定的(尽管至少是八位)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
相关资源
最近更新 更多