另一个问题是关于确定 C 中的奇数/偶数,并且惯用 (x & 1) 方法被正确标记为对于基于补码的系统已损坏,这是 C 标准允许的。
系统真的存在于计算机博物馆之外的“现实世界”中吗?自 1970 年代以来我一直在编码,我很确定我从未遇到过这样的野兽。
真的有人为这样的系统开发或测试代码吗?而且,如果没有,我们应该担心这些事情还是应该将它们与纸带和穿孔卡片一起放入101房间......?
我在遥测领域工作,我们的一些客户拥有仍然使用 1 补码的旧模数转换器。前几天我只需要编写代码将 1 的补码转换为 2 的补码以进行补偿。
所以是的,它仍然存在(但你不会经常遇到它)。
这一切都归结为了解你的根源。
是的,这在技术上是一项古老的技术,我可能会按照其他人在该问题中的建议进行操作,并使用模 (%) 运算符来确定奇数或偶数。但是了解什么是 1s 补码(或 2s 补码)总是一件好事。无论您是否使用过它们,您的 CPU 一直在处理这些事情。所以理解这个概念永远不会有坏处。现在,现代系统做到了,因此您通常不必担心类似的事情,因此它在某种程度上已成为 Programming 101 课程的主题。但是您必须记住,有些人实际上仍然会在“现实世界”中使用它……例如,与普遍看法相反,有些人仍在使用汇编! 不多,但在 CPU 能够理解原始 C# 和 Java 之前,仍然需要有人理解这些东西。
哎呀,你永远不知道什么时候你会发现自己在做一些你真正需要执行二进制数学的事情,而 1s 补码可能会派上用场。
我在 80 年代使用的 CDC Cyber 18 是一台 1s 补码机器,但那是近 30 年前的事了,从那以后我就再也没有见过(然而,那也是我最后一次在非 PC 上工作)
RFC 791 p.14 将 IP 标头校验和定义为:
校验和字段是报头中所有 16 位字的反码和的 16 位反码。为了计算校验和,校验和字段的值为零。
因此,在现实世界中,在发送的每个 IP 数据包中仍然大量使用一个补码。:)
我从来没有遇到过一个人的补码系统,而且我一直在编码,只要你有。
但我确实遇到了 9 的补码系统——HP-41c 计算器的机器语言。我承认这可以被认为是过时的,我认为他们从来没有为这些提供过 C 编译器。
我决定找一个。Unisys ClearPath 系统有一个ANSI C 编译器(是的,他们称其为“美国国家标准 C”,甚至 PDF 文档最后一次更新是在 2013 年。该文档可在线获取;
有符号类型都使用一个补码表示,具有以下属性:
Type | Bits | Range
---------------------+------+-----------------
signed char | 9 | -2⁸+1 ... 2⁸-1
signed short | 18 | -2¹⁷+1 ... 2¹⁷-1
signed int | 36 | -2³⁵+1 ... 2³⁵-1
signed long int | 36 | -2³⁵+1 ... 2³⁵-1
signed long long int | 72 | -2⁷¹+1 ... 2⁷¹-1
值得注意的是,它还默认支持不符合条件的unsigned int
和unsigned long
,范围从0 ... 2³⁶ - 2
,但可以0 ... 2³⁶ - 1
使用编译指示更改为 。
有趣的是,人们在 1993 年在comp.std.c 上提出了同样的问题,没有人能指出当时使用的补码机器。
所以是的,我认为我们可以自信地说,一个人的补语属于我们历史的一个黑暗角落,实际上已经死了,不再是一个问题。
一个人的补充是一个现实世界的问题,还是只是一个历史问题?
是的,它仍然使用。它甚至用于现代英特尔处理器。来自英特尔® 64 和 IA-32 架构软件开发人员手册2A,第 3-8 页:
3.1.1.8 描述部分
然后通过信息部分的数量来描述每条指令。“描述”部分更详细地描述了指令的用途和所需的操作数。
描述部分可能使用的术语摘要:
* Legacy SSE:指 SSE、SSE2、SSE3、SSSE3、SSE4、AESNI、PCLMULQDQ 以及任何未来的指令集,这些指令集引用 XMM 寄存器并在没有 VEX 前缀的情况下进行编码。
* VEX.vvvv。指定源或目标寄存器的 VEX 位域(以 1 的补码形式)。
* rm_field:ModR/M r/m 字段和任何 REX.B
的简写 * reg_field:ModR/M reg 字段和任何 REX.R 的简写