哪些平台具有8位字符以外的功能?


136

char有时,SO上的某人指出(aka'byte')不一定是8位

看来8位char几乎是通用的。我以为对于主流平台,必须有一个8位char以确保其在市场上的生存能力。

从现在和历史上看,什么平台使用的char不是8位,为什么它们与“普通” 8位不同?

在编写代码并考虑跨平台支持时(例如,针对通用库),对于非8位平台值得考虑什么char

过去,我遇到过一些char16位的Analog Devices DSP 。我想DSP是一种利基架构。(然后,在那时,手工编码的汇编器很容易击败了可用的C编译器可以做的事情,因此我在该平台上对C的使用并没有太多的经验。)


9
CDC Cyber​​系列具有6/12位编码。最受欢迎的字符是6位。其余字符使用12位。
Thomas Matthews 2010年

2
PDP-11钉牢了它。可以将字符编码为char的概念已严重过时。
汉斯·帕桑

7
“ PDP-11钉住了它”-您的意思是因为C最初是为8位字节的PDP-11实现的?但是,接下来为具有9位字节的Honeywell机器实现了C。参见K&R版本1。此外,该问题询问的是字符(即字节),而不是字符(一个或多个字节对未询问的东西进行编码)。
Windows程序员2010年

6
DEC-10和DEC-20具有36位字。每个单词有五个7位ASCII字符是很常见的。还使用了六个6位字符。
David R Tribble 2010年

3
@CraigMcQueen:如果我没记错的话,Atmel微控制器的
CodeVision

Answers:


80

char在德州仪器(TI)的C54x DSP上也是16位,例如在OMAP2中。还有其他的16位和32位DSP char。我想我什至听说过24位DSP,但我不记得是什么,所以也许我能想象得到。

另一个考虑因素是POSIX的要求CHAR_BIT == 8。因此,如果您使用的是POSIX,则可以假设它。如果以后有人需要将您的代码移植到POSIX的近似实现中,恰好碰巧拥有您使用的功能,但是大小不同char,这就是他们的不幸。

不过,总的来说,我认为解决此问题通常比考虑问题要容易得多。只需键入CHAR_BIT。如果要使用精确的8位类型,请使用int8_t。嘈杂地,您的代码将无法在不提供实现的编译上进行编译,而不是悄悄地使用您未曾期望的大小。至少,如果我遇到一个我有充分理由假设的案例,那么我会断言。


2
TI C62xx和C64xx DSP也具有16位字符。(在该平台上未定义uint8_t。)
myron-semack 2010年

7
许多用于音频处理的DSP是24位机器。来自On Semi 的BelaSigna DSP(在他们购买AMI Semi之后);飞思卡尔的DSP56K / Symphony Audio DSP(从摩托罗拉分拆后)。
大卫·卡里

2
@msemack C64xx具有用于8/16/32/40和8位字符的硬件
user3528438 2015年

4
而不是assert()(如果这就是你的意思),我会用#if CHAR_BIT != 8... #error "I require CHAR_BIT == 8"...#endif
基思·汤普森

1
@KeithThompson有什么理由不使用static_assert()吗?
Qix-蒙尼卡(Monica)

37

在编写代码并考虑跨平台支持时(例如,针对通用库),对于具有非8位字符的平台,应该考虑哪种考虑?

它并不是按照规则运行时“值得考虑”的事情。例如,在C ++中,标准规定所有字节将具有“至少” 8位。如果您的代码假设字节正好有8位,则您违反了标准。

现在看来这似乎很愚蠢-“ 当然所有字节都有8位!”,我听到你说。但是,许多非常聪明的人依靠的是无法保证的假设,然后一切都破了。这样的例子充斥着历史。

例如,大多数90年代早期的开发人员都认为,特定的无操作CPU定时延迟需要固定的周期数,因此需要固定的时钟时间,因为大多数消费类CPU的功耗大致相当。不幸的是,计算机变得非常快。这就产生了带有“ Turbo”按钮的盒子的兴起-具有讽刺意味的是,其目的是降低计算机的速度,以便可以以合理的速度玩使用延时技术的游戏。


一位评论者问,标准在何处表示char必须至少具有8位。在第5.2.4.2.1节中。本节定义CHAR_BIT最小可寻址实体中的位数,默认值为8。它还表示:

其实现定义的值的大小(绝对值)应等于或大于所示的相同符号。

因此,等于8或更高的任何数字都适合由实现替换为CHAR_BIT


6
至少20年来,我还没有看到Turbo按钮-您真的认为这与问题紧密相关吗?
Mark Ransom

29
@Mark Ransom:这就是重点。开发人员经常依赖目前看来是正确的假设,但这些假设比最初看起来要不稳定。(不能数出我犯了这个错误的次数!)Turbo按钮应该是一个痛苦的提醒,不要做出不必要的假设,当然也不要做出语言标准无法保证的假设,就像它们是不变的事实。
约翰·费米内拉

1
您能否指出在C ++ Standard中说再见至少有8位?这是一个普遍的信念,但是我个人未能在标准中找到它。我在Standard中发现的唯一一件事是,必须由char多于64个的字符来表示字符,但少于128个,因此7位就足够了。
亚当·巴杜拉

6
第18.2.2节为此调用了C标准。在C标准中,它是7.10节,然后是5.4.2.4.1节。C标准中的第22页。
Windows程序员2010年

2
因此,其他答案和评论都提到了具有5位,6位和7位字节的机器。这是否意味着您不能在符合标准的计算机上运行C程序?
杰里·耶利米'18

34

具有36位体系结构的计算机具有9位字节。根据Wikipedia所述,具有36位体系结构的计算机包括:

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

7
还有霍尼韦尔(中国)的机器,例如第二台使用C的机器。见K&R版本1
Windows程序员

5
事实上,DEC-10也有6位字符-你可以收拾这些6到36位字(前DEC-10程序员说话)

2
DEC-20在TOPS-20 O / S上每个36位字使用5个7位ASCII字符。
David R Tribble 2010年

3
该笑话实际上是为在此体系结构上支持Unicode而实现的。
约书亚

9
我想八进制实际上被使用的原因是因为三个八进制数字整齐地表示一个9位字节,就像我们今天通常使用十六进制那样,因为两个十六进制数字整齐地表示一个8位字节。
bames53

18

我知道其中一些:

  • DEC PDP-10:可变,但最常见的是7位字符,每个36位字打包5个字符,否则9位字符,每个字打包4个字符
  • 控制数据大型机(CDC-6400、6500、6600、7600,Cyber​​ 170,Cyber​​ 176等)6位字符,每60位字打包10个。
  • Unisys大型机:9位/字节
  • Windows CE:根本不支持`char`类型-而是需要16位wchar_t

2
@ephemient:我很确定至少有一个PDP-10 / DecSystem 10 / DecSystem 20的(预标准)C编译器。我对CDC大型机的C编译器感到非常惊讶(尽管它们主要用于数字工作,因此Fortran编译器在那里很重要。我很确定其他人确实有C编译器。
杰里·科芬

3
Windows CE编译器真的不完全支持该char类型吗?我知道系统库仅支持带有字符串的函数的广泛char版本,并且至少某些WinCE版本删除了诸如strlen之类的ANSI字符串函数,以阻止您进行char字符串处理。但是它真的根本没有char类型吗?那是sizeof(TCHAR)什么 malloc返回什么类型?Java byte类型是如何实现的?
史蒂夫·杰索普

10
Windows CE支持char,这是一个字节。请参阅Craig McQueen对Richard Pennington的回答的评论。Windows CE与其他任何地方一样需要字节,无论其他地方有多少字节。
Windows程序员

2
PDP-10至少有(两种)C的实现:KCC和gcc端口(pdp10.nocrew.org/gcc)。
AProgrammer

3
C标准不允许每个36位字打包5位7位字符(如您在PDP-10中所述),也不允许如对控制数据大型机提到的6位字符。参见parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.6
肯·布鲁姆

15

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

是的,可能有各种字节/字符大小。是,可以有C / C ++对于具有高度异常值的平台实现CHAR_BITUCHAR_MAX。是的,有时可以编写不依赖于字符大小的代码。

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

好。您可以执行字节顺序转换并将使用的结构成员(例如uint32_t,类似成员)memcpy移入缓冲区。为什么memcpy呢 因为在很多平台上,当目标地址未正确对齐时,就无法写入32位(16位,64位-无差异)。

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

现在是最后一个问题。我们有一个缓冲区。来自它的数据被发送到TCP / IP网络。这种网络假定8位字节。问题是:缓冲区应为哪种类型?如果您的字符是9位的?如果是16位?24?也许每个字符对应一个发送到网络的8位字节,而仅使用8位?还是将多个网络字节打包成24/16/9位字符?这是一个问题,很难相信有一个适合所有情况的答案。很多事情取决于目标平台的套接字实现。

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

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


4
如果每个unsigned char值存储一个八位位组,那么除非代码使用别名技巧而不是通过移位将八位位组的序列与较大的整数类型进行转换,否则应该不会有可移植性问题。就我个人而言,我认为C标准应该定义内在函数,以便从较短类型的序列(最通常为char)中对整数进行打包/解压缩,这些序列存储每项固定的可用保证位数(每8位,每unsigned char16 位unsigned short或每32位unsigned long)。
超级猫



5

例如,C和C ++编程语言将字节定义为“可寻址数据单元,其大小足以容纳执行环境的基本字符集的任何成员”(C标准的第3.6节)。由于C char整数数据类型必须至少包含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

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


1
“虽然还不确定其他语言” –历史上,大多数语言都允许计算机的体系结构定义其自己的字节大小。其实在历史上也是如此C,直到标准设置一个较低的8约束
Windows程序员

4

DEC PDP-8系列有12位字,尽管您通常使用8位ASCII进行输出(大多数情况下是电传打字机)。但是,还有一个6位字符代码,使您可以在单个12位字中编码2个字符。


3

例如,Unicode字符长于8位。如前所述,C规范通过最小大小定义数据类型。如果要查询数据类型并确切发现它们的大小和配置和体系结构,请使用sizeof和中的值limits.h

因此,我会坚持使用数据类型,例如uint16_t当我需要特定位长的数据类型时。

编辑:对不起,我最初看错了您的问题。

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

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

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

考虑多平台支持时,请利用中定义的类型stdint.h。如果你使用(比如)一个uint16_t,那么你可以肯定,这个值是什么架构的16位无符号值,无论是16位值对应于charshortint,或别的东西。大多数艰苦的工作已经由编写您的编译器/标准库的人员完成。

如果您char由于正在执行某种需要它的低级硬件操作而需要知道a的确切大小,那么我通常使用足够大的数据类型来char在所有支持的平台上保存a (通常为16位)并运行convert_to_machine_char当我需要精确的机器表示时,可以通过例程获取值。这样,特定于平台的代码仅限于接口功能,并且大多数时候我可以使用normal uint16_t


2
该问题并未询问字符(无论是否为Unicode)。它询问有关char的信息,这是一个字节。
Windows程序员

1
同样,执行字符集与操作码无关,考虑到交叉编译器,它是执行时使用的字符集。
ninjalj 2010年

“从历史上看,x86平台的操作码只有一个字节长”:多么贴心。 从历史上看,C是在PDP-11(1972年)上开发的,很早就发明了x86(1978年)。
马丁·邦纳

3

对于非8位字符的平台,应该考虑哪种考虑?

幻数出现,例如在换挡时;

通过使用CHAR_BIT和UCHAR_MAX而不是8和255(或类似的值),可以很简单地处理其中的大多数。

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

这些是“常见”问题。

另一个间接问题是说您有:

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

在一个平台上,这可能(仅)占用(最佳情况下)24位,而在其他平台上则可能占用例如72位.....

如果每个uchar都具有“位标志”,并且每个uchar仅具有您当前正在使用的2个“重要”位或标志,并且您仅将它们组织成3个uchar来进行“澄清”,那么它可能相对“更浪费”,例如具有24位uchar的平台.....

位域无法解决所有问题,但它们还有其他需要注意的地方...。

在这种情况下,一个枚举可能是获取您实际需要的“最小”大小的整数的一种方法。

也许不是一个真实的例子,但是当移植/使用一些代码时,这样的东西“有点”我...

实际上,如果uchar的大小是“正常”所期望的大小的三倍,那么在某些平台上100个这样的结构可能会浪费大量内存.....在“正常”情况下,这没什么大不了的。 。

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

这个问题可能会更加突出,例如对于int或其他类型,例如您有一些需要15位的结构,因此您将其粘贴在int上,但在其他平台上int是48位或其他类型。 。

“通常”,您可以将其分成2个uchar,但是例如使用24位uchar,则只需一个即可。

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

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

因此,无论uchar或uint的大小如何,即使代码仍然可以正常工作/运行,也可能会冒出“设计缺陷”。

即使您的代码中没有“魔术数字”,也有一些类似的事情需要提防...

希望这是有道理的:)


1
...什么?您为什么认为enum它可能比其他本机类型小?您知道它默认使用与相同的存储int吗?“您有一些需要15位的结构,因此您将其固定在一个int上,但是在其他平台上,一个int是48位或其他....”-因此#include <cstdint>,使其成为int16_t最大程度地减少位使用的机会。我真的不确定在所有这些椭圆中您以为在说什么。
underscore_d

1

int以前是16位(pdp11等)。进入32位架构非常困难。人们正在变得更好:几乎没有人会认为指针可以再容纳很长时间了(您不对吗?)。或文件偏移量,时间戳或...

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


2
真正。现在这个名称char在Unicode时代有点古朴。在处理二进制数据(例如文件存储,网络通信)时,我更关心8位单元(八位位组)。uint8_t更有用。
Craig McQueen 2010年

3
实际上,Unicode从来不需要完整的32位。他们最初计划使用31位(请参阅最初的UTF-8工作),但是现在他们只满足21位。他们可能意识到,如果他们实际上需要全部31位信息,他们将不再能够印刷这本书:P
me22 2013年

2
@ me22,Unicode最初计划为16位。“ Unicode字符始终为16位宽,与语言无关……” Unicode 1.0.0。unicode.org/versions/Unicode1.0.0/ch01.pdf
香农遣散费

1
ISO 10646最初是31位,而Unicode与ISO 10646合并,因此说Unicode是31位可能有点草率,但这并不是真的。请注意,它们实际上不再打印完整的代码表。
prosfilaes
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.