为什么POSIX规定CHAR_BIT等于8?

33
在POSIX理性中有一条注释称,强制CHAR_BIT为8是必须做出的让步,以保持与C99的对齐而不放弃套接字/网络,但我从未看到过关于冲突具体是什么的解释。是否有人有关于为什么认为这是必要的的轶事或引用?编辑:我得到了很多关于为什么CHAR_BIT应该为8的猜测性答案,并且我同意,但我真正想知道的是C99和POSIX中的网络内容之间的技术冲突是什么。我最好的猜测是,这与C99要求uint * _t成为精确大小的类型(无填充)有关,而先前在POSIX中的inttypes.h没有这样的要求。

6
“因为很多代码会出现问题”是一个好的回答吗? - user541686
2
因为我们已经习惯了这样做! - Ulterior
2
@user:POSIX 做了很多与“大多数程序员习惯的方式”相反的事情,例如 fork。当你学习 fork 时,它与你以前见过的任何东西都不一样。然而,它是 Unix 进程操作模型的核心。 - Billy ONeal
8
我认为你已经回答了自己的问题。如果早期版本的Posix 要求存在uint8_t,但允许它具有填充,并且然后C99出现了,不要求uint8_t存在,但是说如果存在,则必须没有填充,那么如果Posix要纳入C99,则有两个选择 - 取消要求uint8_t存在(这会使原来有效的程序无效),或者要求它没有填充(这会使实现符合标准的实现变得不符合标准)。后者可能是较小的罪恶。 - Steve Jessop
4
stdint.h的POSIX规范中的基本原理部分明确指出,CHAR_BIT == 8是添加int8_t的结果:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdint.h.html。我不知道这个措辞是什么时候添加到POSIX文档中的。 - Michael Burr
显示剩余7条评论
3个回答

12

由于ANSI和ISO中的大多数(与通信相关的)标准都使用八位字节(8位值)来表达,因此不存在那种含糊不清的可变长度字符的废话 :-)

而且,由于相当大量的C代码使用charunsigned char来存储和/或操作这些值,并假定它们的宽度为8位,因此ISO允许变量大小将会导致该代码出现问题。

记住ISO C最重要的目标之一:现有的代码很重要,现有实施不重要。这就是为什么首先存在limits.h而不是仅仅假设特定值的原因,因为周围有些代码认为不同。

POSIX也遵循了同样的指导方针。通过强制字节大小为8位,他们防止了已经在现实世界中大量存在的代码的中断。


2
在中间段落中,“ISO”有点令人困惑,因为ISO是C99的作者(它允许CHAR_BIT != 8),并且稍微不那么出名的是认证Posix标准(不允许)。因此,无论它是否这样做,都会引起问题,具体取决于您所谈论的标准。 - Steve Jessop
抱歉,Steve,我只是想说POSIX有要遵循的指南,就像ISO一样。我会尽力澄清的。 - paxdiablo

9
由于在C语言中,char是最小的可寻址单元,如果将char扩大到8位以上,将难以或无法编写套接字实现,正如你所说。所有网络都在CHAR_BIT == 8机器上运行。因此,如果你从一个CHAR_BIT == 9的机器发送消息到一个CHAR_BIT == 8的机器上,套接字库该怎么处理多出来的一位呢?这个问题没有合理的答案。如果截断这一位,那么即使是向套接字代码的客户端指定像字符数组这样简单的缓冲区也会变得困难--在这样的系统上,“它是一个字符数组,但你只能使用前8位”是不合理的。此外,从8位系统到9位系统也会遇到同样的问题--套接字系统该怎么处理额外的一位呢?如果将该位设置为零,想象一下将一个int放在线上会发生什么。你必须在9位机器上进行各种令人讨厌的位掩码操作才能使其正确工作。
最后,由于99.9%的机器使用8位字符,这并不是很大的限制。大多数使用CHAR_BIT != 8的机器也没有虚拟内存,这将使它们无法与POSIX兼容。
当你在单台机器上运行时(正如标准C所假设的那样),你可以像对待CHAR_BIT不敏感一样处理,因为可能读取或写入数据的两端都同意正在发生的事情。当引入像套接字这样涉及多台机器的东西时,它们必须就字符大小和字节序等事项达成一致。(字节序基本上只是在线上标准化为Big Endian,因为许多架构在字节大小上的差异比字节序还要大)。

POSIX需要虚拟内存吗?我记得阅读过posix_spawn的理由,其中指出“进程太有用了,不能简单地选择退出POSIX,每当它必须在没有地址转换或其他MMU服务的情况下运行时。” - Dietrich Epp
是的,POSIX要求内存保护、共享内存映射文件等。关于posix_spawn的文本是针对实现者希望实现一个严格的非符合自身的POSIX子集。 - R.. GitHub STOP HELPING ICE
2
个人而言,如果我要定义一个与CHAR_BIT无关的套接字API,我将定义所有网络函数以char *缓冲区为参数,但仅读取或写入这些缓冲区的低8位作为网络八位字节。然后,您还需要解决地址和端口号 - 端口257仍必须表示为两个八位字节,即0x0101,因此hton / ntoh被定义为不仅改变字节顺序,还将插入/删除填充位。在两个16位字符机器之间进行通信效率低下,会使用比必要多一倍的内存,但仍胜过没有通信... - Steve Jessop
我可以指出9位模型不仅仅是一个思想实验吗?另外,它还带给我们FTP的type L 8作为交易的一部分。 - geekosaur
@Steve:你真的希望大多数在现代计算机上运行的代码都必须一直这样做吗?对我来说似乎有点极端。 - Billy ONeal
显示剩余10条评论

1

我的猜测:

  • 许多代码通过类似以下的位运算:

    for (int i = 0; i < 8; i++) { ... }
    

    而所有这些都会失败。

  • 大多数其他语言默认是8位,如果不是的话就会彻底崩溃。

  • 即使大多数语言不需要这样做,大多数ABIs仍然会出现问题。

  • 在十六进制中很方便(两个半字节):0xAA

  • 如果你开始这么做,那么你可以考虑:好吧,谁说我们必须使用2状态位?为什么不使用3状态位?等等... 它开始变得越来越不实用了。


有人可能会认为这样的语言/代码是错误的。 (就像C标准(以及C ++标准)一样)通过用CHAR_BIT替换8来轻松修复第一个循环。然而,这是合理的推论,所以+1。 - Billy ONeal
@Billy,我怀疑这段代码大部分是在ANSI/ISO开始进行C语言开发之前编写的。 - paxdiablo
@paxdiablo:那么为什么Posix同意了Mehrdad的论点“它会破坏很多代码”,但ANSI/ISO没有(并允许在C中使用CHAR_BIT !=8)?你是否实际上在说IEEE比ANSI/ISO更关注这个代码?如果是这样,那么基本上就是谁在相关委员会上的运气问题。 - Steve Jessop
换句话说,他们两个都不想破坏代码,只是他们不想破坏的代码集不一定相同。再次强调,这只是我的观点,我没有参加任何工作组。 - paxdiablo
1
@pax:很好,那就不只是运气了。Posix委员会预测未来不会有将16位字符硬件加入操作系统的趋势,而C语言想要在DSP等设备上运行。这个预测几乎是自我实现的,因为既然Posix已经做出了这个要求,任何想要为其构建CPU和Posix操作系统的人都必须使其可寻址8位。无论如何,8-16转换都将非常痛苦,除非Posix改变限制或变得过时 :-) - Steve Jessop
显示剩余3条评论

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