标准委员会关注的异国架构


154

我知道C和C ++标准留下了语言实现定义的许多方面,只是因为如果存在具有其他特征的体系结构,那么将很难或不可能为其编写符合标准的编译器。

我知道40年前,任何计算机都有其自己的独特规范。但是,我不知道今天使用的任何架构在哪里:

  • CHAR_BIT != 8
  • signed 不是两个的补码(我听说Java对此有问题)。
  • 浮点不符合IEEE 754(编辑:我的意思是“不是采用IEEE 754二进制编码”)。

我问的原因是,我经常向人们解释,C ++不要求其他任何低级方面(例如固定大小的类型†)是很好的。很好,因为与“其他语言”不同,它可以使您的代码在正确使用时可移植(编辑:因为可以将其移植到更多体系结构中,而无需模拟机器的低级方面,例如,符号+幅值体系中的二进制补码算法) 。但是我很难为自己不能指出任何特定的体系结构。

所以问题是:哪些架构具有上述特性?

uint*_t是可选的。


9
我想你倒退了。如果C ++要求对带符号整数进行二进制补码,则C ++代码的可移植性将越来越强。为什么C ++标准委员会不强制要求这样做的问题是另一回事。尤其是尽管您说了什么,但并非不可能为非标准体系结构编写编译器,即使您的平台不直接支持8位字符或二进制补码算术,也始终可以模拟8位字符。
约翰

8
@john:那么这是不切实际的,因此非标准的符合条件的编译器会比符合标准的编译器生成更快的代码。而且我仍然看不到它如何使您的代码更具可移植性。
Yakov Galka,2011年

4
我确信标准如此之所以真正的原因不是因为它是一些理想的解决方案。而是因为编写标准时已经存在许多C和C ++编译器,并且标准委员会不希望拒绝现有的编译器。
约翰

4
@john:我怀疑在创建C ++标准时优先考虑“使编译器编写者更容易”(如果这样做的话,它们会做得很糟糕,因为C ++是最难解析的语言之一,而其他方面这种语言也不能使编译器编写者容易地做到这一点)。性能,广泛的平台支持和向后兼容性非常重要。如果将您提到的限制添加到标准中,那么这三者都将受到影响。
桑德·戴克

5
它与编译器无关,而与硬件有关。C ++保留了一些未指定的东西,以允许直接使用硬件功能。您的电话应用程序无论如何都不会在大型机上运行,​​因此无论代码如何,都没有可移植性。
Bo Persson

Answers:


114

看看这个

Unisys ClearPath Dorado服务器

为尚未迁移所有Univac软件的人们提供向后兼容性。

关键点:

  • 36位字
  • CHAR_BIT == 9
  • 一个人的补
  • 72位非IEEE浮点
  • 代码和数据的单独地址空间
  • 字寻址
  • 没有专用的堆栈指针

虽然不知道他们是否提供C ++编译器,但可以


现在,指向他们最新版本的C手册的链接已经浮出水面:

Unisys C编译器编程参考手册

第4.5节列出了具有9、18、36和72位的数据类型。

USC C编译器中数据类型的大小和范围


13
我猜想void *在该体系结构中使用肯定是令人讨厌的。
luiscubal 2011年

13
@ybungalobill-我相信char*并且void*必须大小相同,并且大小足以容纳任何其他指针。其余的取决于实施。
Bo Persson

22
@ybungalobill:在旧的Win16编译器上,常规指针是近指针,并且仅包含16位偏移量,因此sizeof(int*) == 2,但远指针也具有16位选择器,因此sizeof(void*) == 4
亚当·罗森菲尔德

10
他们的C ++编译器已有或曾经有在线手册。还值得指出的是,这只是Unisys大型机架构中的一种:另一种是48位带符号幅度标记的架构(为此,我只找到了C手册,而不是C ++手册)。关于其余部分:我sizeof(int*) != sizeof(char*)在这里不认为:都是36位。但是中的字节选择器位于char*高位,在中被忽略int*。(不过,我使用过其他机器,其中`sizeof(char *)> sizeof(int *)。)
James Kanze 2011年

16
@Adam Rosenfield在MS / DOS 16位编译器上,您具有不同的“模式”,并且数据指针的大小不一定与函数指针相同。但是至少在我使用的那些指针上,所有数据指针(包括void*)始终具有相同的大小。(当然,您不能将函数指针转换为void*,因为它void*可能会更小。但是根据标准,今天也不能这样做。)
James Kanze 2011年

51

您的假设均不适用于大型机。首先,我不知道使用IEEE 754的大型机:IBM使用基数16的浮点,而两个Unisys大型机都使用基数8。Unisys的机器在许多其他方面都有些特殊:Bo提到了2200。架构,但MPS架构甚至更陌生:48位标记的单词。(单词是否为指针取决于单词中的某个位。)并且设计了数字表示形式,以使浮点数与整数算术运算之间没有真正的区别:浮点数以8为底;它不需要规范化,并且与我所见过的所有其他浮点不同,它将小数点放在尾数的右边而不是左边,并对指数(除尾数外)使用带符号的大小。结果是,整数浮点值具有(或可以具有)与带符号的幅度整数完全相同的位表示形式。而且没有浮点运算指令:如果两个值的指数都为0,则该指令执行积分运算,否则执行浮点运算。(体系结构中标记哲学的延续。)这意味着int 可能占用48位,其中8位必须为0,否则该值将不会被视为整数。


4
IBM大型机(z /体系结构)确实支持IEE754浮点。
Nikita Nemkin'6


6
@Nikita-他们现在做。最初,它是一个(昂贵的)附加组件,用于支持Java。
Bo Persson


42

在浮点实现中,完全符合IEEE 754的情况很少。在这方面削弱规范可以进行很多优化。

例如,子规范在x87和SSE之间的支持差异。

源代码中分开的诸如乘法和加法运算之类的优化也略有改变结果,但是在某些体系结构上是很好的优化。

或在x86上,严格的IEEE遵从性可能要求设置某些标志或在浮点寄存器与常规内存之间进行其他传输,以强制其使用指定的浮点类型而不是其内部80位浮点。

而且某些平台根本没有硬件浮动,因此需要在软件中进行仿真。而且,IEEE 754的某些要求在软件中实现可能会很昂贵。特别是舍入规则可能是个问题。

我的结论是,如果您不总是想保证严格的IEEE遵从性,那么您就不需要异国情调的架构来适应各种情况。因此,很少有编程语言可以保证严格遵守IEEE。


7
另一套“特殊的”硬件是IBM大型机,其中的浮点格式早于IEEE标准。与Java不同,C ++仍可以使用现有硬件。
Bo Persson

5
GPU不完全支持IEEE 754。
kerem

3
缺乏对IEEE 754的严格合规性使某些人感到困扰,但是我认为OP真正关心的问题范围不大。
2011年

3
@Matthieu因为它也被标记为“ C”,所以我应该提到一个C分析器,它可以告诉您您的浮点程序可能会采用80位浮点寄存器随C编译器一时兴起而溢出的所有值。blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
Pascal Cuoq

2
@MatthieuM .:太糟了,ISO / ANSI不允许可变参数为浮点数和整数参数指定最小/最大大小;如果有的话,80位long double可能是有用且寿命长的类型,因为它的一个真正的问题是它与不能很好地配合使用printf。扩展双精度存储前导1的事实显着加快了在非FPU系统上的计算速度,并且还消除了在除向其他类型的转换之外的任何情况下对异常的特殊处理的需求。太糟糕了,C printf把一切搞砸了。
supercat 2015年

40

我发现此链接列出了其中的某些系统CHAR_BIT != 8。它们包括

一些TI DSP具有 CHAR_BIT == 16

BlueCore-5芯片(来自Cambridge Silicon Radio的蓝牙芯片)具有CHAR_BIT == 16

当然,关于堆栈溢出还有一个问题:哪些平台具有8位字符以外的内容

对于非二进制补码系统,有关于 comp.lang.c ++。moderated的有趣读物。总结:有些平台具有补码或符号和大小表示。


5
Analog Devices具有32位SHARC DSP CHAR_BIT=32,而TMS32F28xx提供的Texas Instruments DSP具有CHAR_BIT=16。用于PDP-10的GCC 3.2具有CHAR_BIT=9。我认为,S / 360可能也有一个非8位字符。
osgx 2011年

1
我仍然想举一个“非二进制补码”架构的例子。特别是因为发生的CHAR_BITS是部分重复。
Yakov Galka 2011年

TI DSP仅具有16位字符,这是因为实现者选择了它(使其工作正常还需要做更多的工作,但IIRC并不荒唐-可能只是底层编译器的代码生成框架中的一些“漏洞”) 。因此,这不是一些深层的体系结构原因。C代码在抽象机上工作。如果您只有16位INT,则每个中存储两个字符,并向窥视孔优化器添加read-modify-write合并(至少)。当然,这需要更多的工作,但是看看每个人在他们永远不会出现的地方处理这种奇怪类型的工作要多得多。uck
恢复莫妮卡

24

我相当确定VAX系统仍在使用中。它们不支持IEEE浮点数。他们使用自己的格式。Alpha支持VAX和IEEE浮点格式。

尽管更新的Cray系统使用IEEE,但Cray矢量机(如T90)也具有自己的浮点格式。(我使用的T90几年前已经退役;我不知道是否仍在使用中。)

T90还具有/具有一些有趣的指针和整数表示形式。本机地址只能指向64位字。C和C ++编译器的CHAR_BIT == 8(这是必需的,因为它运行的是Unicos,一种Unix风格,并且必须与其他系统进行互操作),但是本机地址只能指向64位字。所有字节级操作是由编译器合成,和一个void*char*存储一个字节的字的高阶3个比特的偏移。而且我认为某些整数类型具有填充位。

IBM大型机是另一个示例。

另一方面,这些特定的系统并不一定要排除对语言标准的更改。对于将C编译器升级到C99,Cray没有表现出特别的兴趣。大概是同样的情况适用于C ++编译器。这可能是合理的收紧不填充比特托管实现的要求,如要求CHAR_BIT == 8,IEEE格式浮点如果不是全部语义,二进制补码符号整数。旧系统可以继续支持较早的语言标准(当C99推出时C90不会消失),并且对于独立的实现(嵌入式系统)(如DSP)的要求可能会更宽松。

另一方面,将来的系统可能有充分的理由来做今天被认为是异国情调的事情。


6
最后要指出的是,过于严格的标准如何阻止创新。当我们获得具有三态的量子(或有机)计算机时,unsigned整数类型的模算术要求将是一个主要的难题,而有符号算术将很好。
Ben Voigt

@BenVoigt为什么无符号算术很痛苦?这些计算机中的3 ^ n加法器不是不可能的吗?
phuclv

2
@LưuVĩnhPhúc:正是这样,硬件操作以模3 ** n进行,要提供C ++无符号类型的操作以模2 ** n定义将是困难的。
Ben Voigt

2
我知道一个VAX 11/780仍在用作交叉编译器的主机,该交叉编译器针对具有专有体系结构的专用嵌入式系统。为了维持特定的VAX,保管人一直在向博物馆索取备用物品。
彼得

2
@Keith-从技术上讲,唯一的障碍是要通过一个过程来提供满足法规要求的证据,因为目标嵌入式系统具有很高的关键性。但是,迄今为止存在许多非技术性障碍(组织政治等)是无法克服的。目前,装箱袭击博物馆要比更新主机容易。
彼得

16

CHAR_BITS

根据gcc的源代码:

CHAR_BIT16对位1750Adsp16xx架构。
CHAR_BITdsp56k架构的24位。是c4x架构的位。
CHAR_BIT32

您可以通过执行以下操作轻松找到更多信息:

find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"

要么

find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"

如果CHAR_TYPE_SIZE已正确定义。

符合IEEE 754

如果目标体系结构不支持浮点指令,则gcc可能会默认生成不符合标准的软件后备代码。不仅如此,-funsafe-math-optimizations还可以使用特殊选项(例如女巫也禁用符号保留为零)。


3
赞成仅指示OP查看流行编译器的源代码;在这种情况下,这就是RFTM的定义,因此它应该是人们首先关注的地方。
underscore_d

9

直到最近,IEEE 754二进制表示形式在GPU上才很常见,请参阅GPU浮点偏执狂

编辑:注释中提出了一个问题,即GPU浮点是否与通常的计算机编程相关,而与图形无关。当然好!当今工业上计算出的大多数高性能都是在GPU上完成的。该列表包括AI,数据挖掘,神经网络,物理模拟,天气预报等。一位在评论节目,为什么链接:一个数量级浮点图形处理器的优势。

我想补充一件事,这与OP问题更相关:当GPU浮点不是IEEE且没有像今天的OpenCL或CUDA这样的API来编程GPU时,人们在10-15年前做了什么?信不信由你,早期的GPU计算先驱设法在没有API的情况下对GPU进行编程!我在公司里遇到了其中一位。这就是他的工作:他将需要计算的数据编码为图像,并用像素表示他正在处理的值,然后使用OpenGL执行他需要的操作(例如“高斯模糊”以正态分布表示卷积)等),然后将生成的图像解码回结果数组。而且这仍然比使用CPU快!

诸如此类的事情促使NVidia最终使内部数据与IEEE二进制兼容,并引入了面向计算而非图像处理的API。


GPU有何关联?(a)此页面似乎非常过时。(b)直到今天,您仍无法在C语言中对GPU进行编程:因为C支持递归函数之类的东西,就我所知,GPU还不支持。因此,如果您愿意,甚至无法编写编译器。
Yakov Galka '16

1
@ybungalobill,将重复工作转移到GPU是当前进行大规模计算的首选方法。实际上,我目前正在用C ++开发一个。幸运的是,我们只能使用具有IEEE 754兼容浮点数二进制表示形式的NVidia CUDA GPU。
迈克尔

我不是说GPU不用于GP计算。我说过,尽管语法相似,但您实际上并没有用C编写内核。可以int f(int n) { return n <= 1 ? 1 : n * f(n-1); }在CUDA中执行吗?如果不是,那么GPU与这个问题(询问C和C ++委员会)无关。
Yakov Galka '16

6
@ybungalobill:几个答案。首先,CUDA确实支持C,C ++和Fortran。有关2048线程GPU与典型的8线程CPU相比的巨大性能优势,请参见同一链接。其次,是的,仅支持这些语言的子集(尽管很大),包括直到CUDA 5.0才缺少适用于CUDA编程模型递归的支持(称为“动态并行性”)。第三,递归通常可以用循环来代替,这对于多线程性能而言是必不可少的。
迈克尔
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.