【问题标题】:signed as default in C在 C 中签名为默认值
【发布时间】:2013-09-04 12:21:59
【问题描述】:

再一次,我正在教一门课,我可以回答学生关于 C 的问题。这是一个我不知道答案的问题:接受 signed 作为 C 的默认修饰符是否有理由?人们会认为unsigned 是自然选择。那么,这真的是一个设计决定吗?

【问题讨论】:

  • “基本原理”本身并不完全正确。对于普通的char,并不总是signed
  • 为什么 unsigned int 会更自然?我认为大多数现实世界的问题都涉及正面和负面的价值。
  • @jxh 更重要的是,大多数现实世界的问题都处理 small 数字 - 即相对接近 0 的数字。我认为大多数人在大多数情况下更有可能需要低于(或至少接近)0 的数字,那么他们需要大于(或什至接近)MAX_INT 的数字。有符号数字的上限和下限都尽可能远离最常用的数字。

标签: c standards


【解决方案1】:

标准而言(因为您的问题被标记为这样),signed 被标记为默认值,因为这就是 之前的 C 实现 em> 标准。

最初的 ANSI/ISO 标准要求是编纂现有实践,而不是创建一种新语言。因此,根据基本原理文档,预标准实现的行为是最重要的因素:

最初的 X3J11 章程明确要求编纂现有的常见做法,C89 委员会坚持先例,只要这是明确和明确的。

C89 定义的绝大多数语言与 Brian Kernighan 和 Dennis Ritchie 在 The C Programming Language 第一版的附录 A 中定义的完全相同,并且在当时几乎所有 C 翻译器中都实现了这一点。 (本文档以下简称K&R。)

如果您想了解为什么预标准实现首选 signed,您可能需要研究最初开发 UNIX 和 C 的 PDP-n 机器的架构。

History of C 页面显示 unsigned 实际上是该语言的相对较晚者,出现在 70 年代中期:

在 1973-1980 年间,该语言有所发展:类型结构获得了 unsigned、long、union 和枚举类型,并且结构几乎成为一流的对象(仅缺少文字符号)。

【讨论】:

  • 哈。那很有意思。我倾向于这个答案,但请注意,它仍然有些问题:为什么以前的 C 实现会将 signed 作为默认值?
  • @Dervin,为什么不呢? signed 类型适用于正值和负值,在日常生活中使用。
  • @Eric,对,只是我认为修饰符是同时出现的(我的假设是错误的),所以如果我处于语言设计阶段,我会制作 char未签名,并要求程序员明确告诉我他/她想要其他方式。历史真有趣!
  • 根据维基百科,C 是为 PDP-7 开发的,但我确信 K&R 确实在早期的计算机上工作过,并且深受 BCPL 语言的影响。
  • @Dervin,是的,作为为数不多的在 BCPL 编译器中工作和实现的代码猴子之一 :-),相似之处远大于差异(至少对于早期的 C 语言)。但它在当时是一门美丽的语言,我把 MartinR 和 dmr 放在了一起。是的,它最初是 PDP7,尽管他们很快不得不将其移植到其他机器上,包括 IBM 的 big iron。
【解决方案2】:

这主要是关于向后兼容性,以及 C 从早期语言的血统,这些语言不能轻易支持有符号和无符号整数。

C 源自一种称为 B 的旧语言,而 B 源自一种更古老的语言 BCPL(它是 CPL 的简化版本)。

BCPL 基本上是一种无类型的语言。变量声明没有指定对象的类型;相反,对给定变量的操作会将其视为给定类型。

BCPL 运算符+-*/REM 将其操作数视为 有符号 整数,并产生整数结果。

如果 BCPL 支持无符号整数,那么它要么必须有另一组无符号操作数的运算符,要么根本无法表示负数。 (注意 BCPL 不支持浮点。)

B 的语法与 BCPL 的完全不同(更接近于 C 的),但它保留了许多相同的语义。特别是,变量和函数默认是整数类型——并且没有unsigned关键字。

基于 B 的早期 C 也没有 unsigned 关键字。它只有四种基本数字类型:charintfloatdouble。 (添加了unsigned,以及longunionenum,在 1973 年到 1980 年之间的某个时间。)鉴于语言的弱类型特性,程序员有时在需要无符号算术时使用指针。

没有声明类型的实体隐式属于int 类型的“特征”一直保留在 C 中,直到 1999 年 ISO 标准最终删除了“隐式 int”规则。

此外,有符号整数类型往往比无符号类型更有用。表示负值的能力非常方便。鉴于典型的环绕语义,两个小值的无符号减法中的错误可能会产生一个巨大的正值(例如,3 - 4 == 65535,对于 16 位无符号类型)。即使在作为所有这些语言的主要目标的系统编程领域,有时也需要表示负值(例如某个数量的变化)。

参考资料:

【讨论】:

    【解决方案3】:

    根据The Development of the C Language,unsigned 的概念是在 1973 年至 1980 年间添加功能时对该语言的扩展。虽然没有明确说明,但叙述表明它直到 1977 年才引入(参见 可移植性,第 3 段)。

    因此,默认为有符号是因为该语言最初只有有符号类型。

    【讨论】:

      【解决方案4】:

      char 的默认签名不是由语言定义的。它由实现定义。有些 CPU 更自然地是有符号的 char,而另一些 CPU 更自然地是无符号的。

      【讨论】:

      • “自然”签名是什么意思?
      • @DervinThunk:将 8 位数量扩展到 16 位或更大的指令的自然性具有内置的特定假设,尤其是大约 1985 年左右之前的 CPU。在 unnatural 方向上将 char 提升为 int 需要额外的指令来实现。 自然方向只需要一条指令。
      • @wallyk,您确定标准不强制要求纯 int 的签名吗?我记得该标准确实要求int 可以表示的值的最小范围。见stackoverflow.com/questions/6155784/…
      • 这仅适用于普通的char。普通int总是有符号(位字段除外,其中普通int具有实现定义的符号)。
      • @EricZ:我认为最初的问题是关于char 的默认签名。我已经在我的回答中明确表示了。
      【解决方案5】:

      unsigned 语义保证更简单:以 2 为模n 没有例外。但是不要对 n 是什么做任何假设:范围的大小不需要等于对应的有符号类型的大小。

      唯一的要求是所有正符号值也可以用对应的无符号类型来表示。

      unsigned 的一个有效实现是使用二进制补码有符号算术,并在每次操作后将符号位清零。这不太可能出现在现实生活中,但使用非补码算法的机器在绕过负数逻辑时可能会遇到更多麻烦。

      实际上,负数是任何硬件平台的基本特征,但将整个寄存器视为正数的能力只是锦上添花。 C 旨在最紧密地包裹硬件中最高效的部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-08-01
        • 2022-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多