新的C ++标准仍然拒绝指定整数类型的二进制表示。这是因为C ++的实际实现不使用2的补码算法吗?我觉得很难相信。是不是因为委员会担心硬件的未来发展会让“过时”的概念变得过时?再次难以置信。任何人都可以对此有所了解吗?
背景:我在一个评论帖中惊讶了两次(Benjamin Lindley对this question的回答)。首先,来自piotr的评论:
签名类型的右移是未定义的行为
其次,来自James Kanze的评论:
当分配给long时,如果该值不适合long,则结果为 实施定义
在我相信之前,我必须在标准中查看这些内容。它们的唯一原因是适应非二进制补码整数表示。为什么?
答案 0 :(得分:23)
定义不合适的东西的一个主要问题是编译器是在未定义的情况下构建的。改变标准不会改变编制者并审查那些编制者以找出假设的位置是一项艰巨的任务。
即使在2台补充机器上,你的变化也可能超出你的想象。两个例子:一些没有保持右移的符号,只有一个引入零的右移; DSP中的一个共同特征是饱和算术,指定超出范围的值会将其剪切为最大值,而不仅仅是丢弃高位。
答案 1 :(得分:4)
我想这是因为标准所说的3.9.1[basic.fundamental]/7
本国际标准允许2的补码,1的补码和积分类型的带符号幅度表示。
我愿意打赌,来自C编程语言,其中列出了符号和幅度,两个补码和一个补码作为6.2.6.2/2
中唯一允许的表示形式。当C广泛传播时,确实存在1的补充系统:似乎最常提到的是UNIVAC。
答案 2 :(得分:4)
在我看来,即使在今天,如果你正在编写一个广泛适用的C ++库,你期望在任何机器上运行,那么就不能假设2的补码。 C ++被广泛用于做出类似的假设。
但是大多数人并没有写那些类型的库,所以如果你想依赖2的补码你应该继续。
答案 3 :(得分:1)
语言标准的许多方面都是正确的,因为标准委员会一直非常不愿意禁止编译器以现有代码可能依赖的方式行事。如果存在依赖于补码行为的代码,那么要求编译器表现得就像底层硬件使用两个补码一样,这将使旧代码无法使用更新的编译器运行。
标准委员会尚未认为适合实施的解决方案是允许代码以独立于机器字大小或硬件特征的方式为事物指定所需的语义。如果对依赖于某些“ - 补充行为”的代码的支持被认为是重要的,那么设计一种代码可以明确地要求补充行为的方法,而不管底层硬件平台如何。如果需要,为避免使每个编译器过于复杂,请指定标准的某些方面是可选的,但符合要求的编译器必须记录它们支持的方面。这样的设计将允许编译器的编译器支持两个补码行为和一个补充行为,这取决于程序的需要。此外,它可以将代码移植到具有编译器的两台补充机器中,这些编译器恰好包含了一些补充支持。
我不确定为什么标准委员会还没有允许任何方式代码可以以独立于底层架构和字大小的方式指定行为(因此代码不会有一些机器使用签名语义进行比较,其他机器将使用无符号语义),但无论出于何种原因,他们还没有这样做。支持一个' - 补充表示只是其中的一部分。