在非二进制补码系统中,普通的char类型通常/总是无符号的吗?

9

显然,标准对此没有任何说明,但从实践/历史的角度来看,我更感兴趣:非二进制补码算术系统是否使用无符号的普通char类型?否则,你可能会遇到各种奇怪的问题,比如空终止符的两种表示形式,以及无法用char表示所有“字节”值。这种奇怪的系统确实存在吗?


1
请注意,当您考虑到strcmp需要将字节比作unsigned char,但可能必须在任一字符串中达到(任一)空终止符字节时停止比较时,奇怪的问题变得更加严重。 - R.. GitHub STOP HELPING ICE
这种奇怪的系统真的存在/存在过吗?我认为不是。 - GolezTrol
3个回答

6

用于终止字符串的空字符永远不可能有两种表示方式。这是这样定义的(即使在C90中也是如此):

一个所有位都设置为0的字节,称为空字符,必须存在于基本执行字符集中。

因此,在一种补码中的“负零”行不通。

话虽如此,我对非二进制补码的C实现并不了解。很久以前在大学里我使用过一种补码机器,但我不记得太多关于它的事情了(即使当时我关心标准,那也是在它出现之前)。


我同意它不会出现在字符串字面值或字符串函数中,但是如果通过算术运算得到负零并将其分配到字符数组中尝试终止字符串,你可能会认为已经终止了它,但实际上失败了...因此,任何表现出这种行为的代码可能存在轻微的可移植性缺陷... - R.. GitHub STOP HELPING ICE

5
在商业计算机(20世纪50年代和60年代)首次生产的头10或20年中,关于如何在二进制中表示负数似乎存在一些分歧。实际上有三种做法:
  1. 补码,不仅赢得了战争,还使其他两种方法灭绝了。
  2. 反码,-x == ~x
  3. 原码,-x = x ^ 0x80000000
我认为最后一个重要的反码机器可能是CDC-6600,在当时是地球上最快的机器,也是第一台超级计算机的前身。
不幸的是,你的问题实际上无法回答,不是因为这里没有人知道答案 :-) 而是因为从来没有必须做出选择。这实际上有两个原因:
  1. 随着字节机器的问世,补码同时掌握了主导权。IBM System/360推出了补码字节寻址。以前的机器没有字节,只有完整的单词有地址。有时程序员会在这些单词中打包字符,有时他们只会使用整个单词。(单词长度从12位到60位不等。)
  2. C语言直到字节机器和补码转换十年后才被发明。项目1发生在20世纪60年代,C语言首次出现在小型机器上,直到20世纪80年代才占据主导地位。
因此,从来没有一台机器拥有带符号字节、C编译器和不同于补码数据格式的东西。空终止字符串的想法可能是一个又一个汇编语言程序员想出的设计模式,但我不知道它是否在C时代之前就已经被指定为编译器。
无论如何,第一个实际上标准化的C(“C89”)只是规定“将值为零的字节或代码附加”,很明显他们试图独立于数字格式。因此,“+0”是一个理论答案,但在实践中可能从未真正存在过。
6600是历史上最重要的机器之一,不仅因为它快,还因为它是Seymour Cray本人设计的,引入了乱序执行和其他后来统称为“RISC”的元素。尽管其他人试图声称功劳,但Seymour Cray才是RISC架构的真正发明者。毫无争议地,他是超级计算机的发明人。实际上很难列出他没有设计的过去的“超级计算机”。

真的没有使用补码或符号-大小表示法的C语言实现吗?如果不存在这样的实现,那么C标准为什么要允许它们呢?毕竟,它们显然是一个很大的麻烦。 - R.. GitHub STOP HELPING ICE
@R,没有实现者会关心这个问题,当然,因为这很烦人,但标准委员会通常不是实现者。他们视自己的任务为定义一种通用语言。毕竟,C语言被称为“可移植汇编语言”,我相信他们想象了在大型机制造商处实施C语言的崩溃程序。真正的原因可能是这样的:在1989年,所有这些价值百万美元的机器变得非常快,并不仅仅是老旧,而是成为了“必须支付某人才能拖走的废料”。事实证明,在“昂贵的填房计算机”和“有毒废物”之间只有一条细线。 - DigitalRoss
我认为他们已经遇到了“-0!= 0”问题。据我所知,您可以执行诸如添加0 + -0并获得真正的零之类的操作,因此在比较之前常常这样做。我怀疑情况会有些像今天的有符号和无符号类型,并且“-0”绝对不会是字符串终止符。 - DigitalRoss
@R.. - 直到21世纪,Univac/Unisys仍在生产反码硬件。如果C语言委员会因为不兼容的字符串终止符而使其在他们的机器上无法实现,那将是相当糟糕的! - Bo Persson
@Bo:永远不是不可能的。即使硬件是为补码而设计的,您仍然可以始终使用二进制补码,只需在生成机器代码时忽略有符号指令并始终生成无符号指令即可。乘法和除法需要一些小的修补,但基本算术是可以的。 - R.. GitHub STOP HELPING ICE

2
我认为系统几乎但并非完全不可能拥有一种补码的“char”类型,但存在四个问题无法全部解决:
  1. 每种数据类型必须可表示为char序列,以便如果组成两个对象的所有char值比较相同,则包含在问题中的数据对象将相同。
  2. 每种数据类型也必须可表示为“unsigned char”的序列。
  3. 任何数据类型可以分解为的无符号字符值必须形成一个阶次是2的幂的群。
  4. 我不相信标准允许补码机器特殊处理将会是负零的值,并使其行为像其他东西。
如果只有通过覆盖其他数据类型才能获得负零,并且如果负零与正零不相等,则可能存在一种符合标准的机器,该机器具有补码或符号-大小写的“char”类型。 我不确定是否符合标准。
编辑
顺便说一下,如果放宽要求#2,我想知道在将其他数据类型叠加到“char”上时确切的要求是什么?除其他事项外,尽管标准明确指出必须能够对任何从另一个变量叠加到“char”上的'char'值执行赋值和比较,但我不知道它是否强制要求所有这些值都必须表现为算术群。例如,我想知道每个内存位置都以66位物理存储的机器的合法性如何,其中顶部两位指示该值是64位整数、32位内存句柄加32位偏移量还是64位双精度浮点数?由于标准允许实现在算术计算超过有符号类型的范围时执行任何喜欢的操作,因此这表明有符号类型不一定要表现为群。
对于大多数有符号类型,没有要求该类型无法表示在limits.h中指定范围之外的任何数字;如果limits.h指定最小“int”为-32767,则实现实际上可以允许一个值为-32768,因为任何尝试这样做的程序都会引发未定义行为。关键问题可能是,从覆盖其他类型得出的'char'值是否产生超出limits.h指定范围的值。我想知道标准说了什么?

你在哪里得到了1和2?我只知道2。 - R.. GitHub STOP HELPING ICE
@R.. - 这并不是等价的。如果字符表示相同,则值相同。但是,如果存在填充位,即使字符表示不同,它们也可能相等。 - Bo Persson
字符类型,至少包括“unsigned char”,根据定义不能有填充位。 - R.. GitHub STOP HELPING ICE
@R: ...故意错误设置某些字节的奇偶校验数据(并利用读取这些字节时可能发生的NMI来捕获对未初始化数据的读取),但符合标准的程序无法显式控制这些位或检测它们的存在。 - supercat
事实上,正如你所说的原因以及其他许多原因一样,C语言基本上排除了垃圾回收。这与它是否交互无关。请记住,您也可以自由加密或哈希指针,或将它们的位分散到各个地方,然后稍后重新组装它们。 - R.. GitHub STOP HELPING ICE
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接