什么平台除了8位 char 还有其他东西?

时不时地,有人指出 char(又名‘ byte’)不一定是8位

似乎8位 char几乎是通用的。我认为对于主流平台来说,有必要使用8位 char来确保它在市场上的生存能力。

现在和历史上,什么平台使用的 char不是8位,为什么他们会不同于“正常的”8位?

在编写代码和考虑跨平台支持(例如通用库)时,对于具有非8位 char的平台,应该考虑哪些因素?

在过去,我遇到过一些 char为16位的模拟设备 DSP。我认为 DSP 是一种小众体系结构。(话又说回来,当时手工编码的汇编程序很容易就打败了现有的 C 编译器,所以我在那个平台上并没有获得太多 C 方面的经验。)

24124 次浏览

例如,C 和 C + + 编程语言将 byte 定义为“大到足以容纳执行环境中基本字符集的任何成员的可寻址数据单元”(C 标准的条款3.6)。由于 C 字符整数数据类型必须至少包含8位(子句5.2.4.2.1) ,因此 C 中的一个字节至少能够保存256个不同的值。C 和 C + + 的各种实现都将字节定义为8、9、16、32或36位

引自 http://en.wikipedia.org/wiki/Byte#History

不过其他语言就不一定了。

Http://en.wikipedia.org/wiki/ibm_7030_stretch#data_formats

将该机器上的字节定义为可变长度

在编写代码和考虑跨平台支持(例如通用库)时,对于非8位 char 的平台值得考虑哪些因素?

与其说它是“值得考虑的”,不如说它是在按规则行事。例如,在 C + + 中,标准规定所有字节都将有“至少”8位。如果您的代码假设字节只有8位,那么您就违反了标准。

现在看来可能有点傻——“ 当然所有字节都有8位!”,我听到你说。但是很多非常聪明的人依赖于不是保证的假设,然后一切都破灭了。这样的例子在历史上比比皆是。

例如,大多数90年代早期的开发人员认为,一个特定的无操作 CPU 计时延迟采取固定数量的周期将采取固定数量的时钟时间,因为大多数消费 CPU 在功耗上大致相当。不幸的是,计算机速度变得非常快。这催生了带有“ Turbo”按钮的盒子的兴起——具有讽刺意味的是,它的目的是让计算机运行速度变慢,以便使用时间延迟技术的游戏可以以合理的速度进行。


一位评论者问道,在标准中,char 必须至少有8位。在 翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳区。本节定义 CHAR_BIT,即最小可寻址实体中的位数,默认值为8。它还表示:

它们的实现定义的值在大小(绝对值)上应等于或大于所显示的值,并具有相同的符号。

因此,任何等于8或更高的数字都可以被实现替换到 CHAR_BIT中。

36位结构的机器有9位字节。根据 Wikipedia,具有36位结构的机器包括:

  • 数字设备公司 PDP-6/10
  • IBM 701/704/709/7090/7094
  • UNIVAC 1103/1103A/1105/1100/2200,

其中有几个我知道:

  • DEC PDP-10: 可变的,但是最常见的是每36位字包含5个7位字符,或者每个字包含4个9位字符
  • Control Data 大型机(CDC-6400,6500,6600,7600,Cyber 170,Cyber 176等)6位字符,每60位字打包10个。
  • Unisys 大型机: 9位/字节
  • WindowsCE: 根本不支持“ char”类型——而是需要16位 wchar _ t

整型过去是16位(pdp11等)。进入32位体系结构是困难的。人们正在变得越来越好: 几乎没有人认为一个指针会再适合一个长指针了(你不这样认为吗?).或者文件偏移,或者时间戳,或者..。

8位字符已经有点不合时宜了。我们已经需要32位来容纳世界上所有的字符集。

看起来你仍然可以把 买一个 IM6100(即芯片上的 PDP-8)从仓库里拿出来。这是一个12位的架构。

char在 Texas Instruments C54x DSP 上也是16位的,例如在 OMAP2中就出现了这种情况。还有其他16位和32位 char的 DSP。我想我甚至听说过24位 DSP,但我不记得是什么,所以可能是我想象出来的。

另一个考虑因素是 POSIX 强制 CHAR_BIT == 8。因此,如果您正在使用 POSIX,那么可以假定它是。如果以后有人需要把你的代码移植到 POSIX 的接近实现的地方,那么碰巧你使用的函数大小不同,这是他们的坏运气。

不过,总的来说,我认为解决这个问题总是比考虑它更容易。输入 CHAR_BIT。如果需要精确的8位类型,请使用 int8_t。在没有提供代码的实现上,您的代码将无法编译,而不是默默地使用您意想不到的大小。至少,如果我碰到一个案子,我有充分的理由假设它,然后我会坚持它。

首先,Unicode 字符长于8位。正如前面提到的,C 规范通过数据类型的最小大小来定义数据类型。如果希望查询数据类型并确切地发现它们对于配置和体系结构的大小,请使用 sizeoflimits.h中的值。

出于这个原因,当我需要一个特定位长度的数据类型时,我尝试坚持使用像 uint16_t这样的数据类型。

编辑: 对不起,我一开始误解了你的问题。

C 规范说,char对象“大到足以存储执行字符集的任何成员”。limits.h列出了8位的最小大小,但是定义保留了 char的最大大小。

因此,char至少与体系结构执行集中的最大字符一样长(通常四舍五入到最接近的8位边界)。如果您的体系结构具有较长的操作码,则 char大小可能更长。

从历史上看,x86平台的操作码是一个字节长,所以 char最初是一个8位值。当前的 x86平台支持比一个字节长的操作码,但是 char保持8位的长度,因为这是程序员(以及大量现有 x86代码)所习惯的。

当考虑多平台支持时,利用 stdint.h中定义的类型。如果您使用(例如)一个 uint16 _ t,那么您可以确定这个值在任何架构上都是一个无符号的16位值,无论这个16位值对应于 charshortint或其他什么。大部分艰苦的工作已经由编写编译器/标准库的人员完成了。

如果你需要知道一个 char的确切大小,因为你正在做一些低层次的硬件操作,需要它,我通常使用一个数据类型,大到足以容纳一个 char在所有支持的平台(通常16位是足够的) ,并通过一个 convert_to_machine_char例程运行的价值,当我需要确切的机器表示。这样,特定于平台的代码仅限于接口函数,大多数时候我可以使用普通的 uint16_t

许多 DSP 芯片都有16位或32位的 char。 TI 公司通常制造这样的芯片 比如说

DEC PDP-8系列有一个12位的单词,尽管您通常使用8位 ASCII 作为输出(主要在电传打字机上)。但是,还有一个6-BIT 字符代码,允许您在一个12位单词中编码2个字符。

对于使用非8位 char 的平台,应该考虑哪些因素?

神奇的数字出现,例如移动时;

其中大部分都可以很简单地处理 通过使用 CHAR _ BIT 和例如 UCHAR _ MAX 而不是8和255(或类似的)。

希望您的实现定义了这些:)

这些都是“常见”问题... ..。

另一个间接的问题是:

struct xyz {
uchar baz;
uchar blah;
uchar buzz;
}

这可能“只”需要(最好的情况下)24位在一个平台上, 但是可能在其他地方采用例如72位... ..。

如果每个 uchar 持有“位标志”,并且每个 uchar 只有2个“有效”位或标志 你只是为了“清楚”才把它们分成了3个 Uchars, 那么它可能相对“更浪费”,例如在一个有24位 uchars 的平台上... ..。

没有什么是位域解决不了的,但是他们还有其他的事情要注意 为了..。

在这种情况下,只有一个枚举可能是获得“最小”的一种方法 实际上你需要的是... 。

也许不是一个真正的例子,但是像这样的东西在移植/使用一些代码时“咬”了我... ..。

事实上,如果一个 uchar 是“正常”期望值的三倍大, 100个这样的结构可能会在某些平台上浪费大量内存... ..。 “通常”这不是什么大问题... ..。

因此,事情仍然可以被“破坏”,或者在这种情况下“很快地浪费了大量的内存” 假设一个 uchar 在一个平台上,相对于可用的 RAM,比在另一个平台上“不是很浪费”... ..。

这个问题可能更加突出,例如对于 int 类型或者其他类型, 例如你有一个需要15位的结构所以你把它放在一个 int 中, 但是在其他平台上,int 是48位的... ..。

“通常”你可以把它分成2个 uchar,但是比如24位 uchar 你只需要一个..。

因此枚举可能是更好的“通用”解决方案... ..。

取决于你如何访问这些位:)

因此,可能会有“设计缺陷”出现在他们的头上... ..。 即使代码仍然可以正常工作/运行,不管 尺寸为 uchar 或 uint..。

有这样的事情要注意,即使有 在你的代码里没有“神奇的数字”。

希望这能说得通:)

没有完全可移植的代码。 : -)

是的,可能有不同的字节/字符大小。是的,可能会有针对 CHAR_BITUCHAR_MAX这两个非常特殊值的平台的 C/C + + 实现。是的,有时可以编写不依赖于字符大小的代码。

然而,几乎所有真正的代码都不是独立的。例如,您可能正在编写一个代码,发送二进制消息到网络(协议并不重要)。您可以定义包含必要字段的结构。然后再连载。仅仅将结构复制到输出缓冲区中的二进制文件是不可移植的: 通常您既不知道平台的字节顺序,也不知道结构成员的对齐方式,因此结构只保存数据,但不描述数据应该序列化的方式。

好吧。您可以使用 memcpy执行字节顺序转换并将结构成员(例如 uint32_t或类似的)移动到缓冲区中。为什么是 memcpy?因为在很多平台上,当目标地址没有正确对齐时,不可能编写32位(16位,64位——没有区别)。

因此,为了实现可移植性,您已经做了很多工作。

最后一个问题。我们有缓冲。数据从它发送到 TCP/IP 网络。这种网络采用8位字节。问题是: 缓冲区应该是什么类型的?如果你的字符是9位的?如果它们是16位的呢?24岁?也许每个字符对应一个8位字节发送到网络,只使用8位?或者可能多个网络字节被打包成24/16/9位字符?这是一个问题,很难相信有一个适合所有情况的单一答案。目标平台的很多事情都依赖于套接字实现。

所以,我说的是。通常编写代码相对容易。如果您希望在不同的平台上使用代码,那么这样做非常重要。但是,提高可移植性超出了这个标准,这是一件需要付出大量努力的事情,而且往往付出很少作为实际代码几乎总是依赖于其他代码(上面示例中的套接字实现)。我确信,对于大约90% 的代码来说,使用8位以外的字节在平台上工作的能力几乎是无用的,因为它使用的是绑定到8位的环境。只需检查字节大小并执行编译时断言即可。几乎可以肯定,对于一个极不寻常的平台,您将不得不重写大量内容。

但是如果您的代码高度“独立”——为什么不呢?您可以以允许不同字节大小的方式编写它。

我见过最奇怪的是疾控中心的电脑。6位字符,但使用 65编码。[还有不止一个字符集——在安装操作系统时选择编码。]

如果一个60位的单词以12、18、24、30、36、40或48位的零结尾,那就是行字符的结尾(例如 '\n')。

因为在某些代码集中,00(八进制)字符是 :,这意味着如果 ::出现在错误的列中,那么使用 ::=的 BNF 就会很尴尬。[这早在 C + + 和 ::的其他常见用法之前就有了。]

Univac 1100系列有两种操作模式: 6位 FIELDATA 和9位“ ASCII”分别在36位文字中包装6个或4个字符。您在程序执行时(或编译时)选择了模式我已经很多年没有在这上面工作了。