43

这不是推荐做法的问题(也不是未定义的行为),而是关于c++标准在将整数类型的所有字节转换为(unsigned char)0.


问题

在下面的片段中,if 语句使用的表达式是否保证在true

std::memset (
  reinterpret_cast<char*> (&a), // int a;
  (unsigned char)0,
  sizeof (int)
);

if (a == 0) {
  ...
}

通过阅读 C99 和 C++11 标准的引用(在这篇文章的后面),我们发现 C99 明确保证所有位都设置为的整数类型0将表示该0类型中的值。

我在 C++11 标准中找不到这个保证。

  • 没有这样的保证吗?
  • 上一个片段的结果真的是特定于实现的吗?


在 C99 中 (ISO/IEC 9899:1999)

5.2.1.2/1 多字节字符

所有位为零的字节应解释为与移位状态无关的空字符。这样的字节不应作为任何其他多字节字符的一部分出现。

6.2.6.2/1 整数类型

任何填充位的值都是未指定的。45)符号位为零的有符号整数类型的有效(非陷阱)对象表示是相应无符号类型的有效对象表示,并且应表示相同的值。

对于任何整数类型,所有位都为零的对象表示应是该类型中值零的表示。



在 C++11 中 (ISO/IEC 14882:2011)

2.3/3 字符集 [lex.charset]

基本执行字符集和基本执行宽字符集应分别包含基本源字符集的所有成员,加上表示警报、退格和回车的控制字符,加上一个空字符(分别为空宽字符),其表示全为零位

4

4 回答 4

14

C++ 11

我认为相关的部分是

3.9.1/1 在 C++11 中

对于字符类型,对象表示的所有位都参与值表示。对于无符号字符类型,值表示的所有可能的位模式都表示数字。这些要求不适用于其他类型。

随着 3.9.1/7

整数类型的表示应使用纯二进制计数系统定义值。

C11

6.2.6.2 非常明确

对于 unsigned char 以外的无符号整数类型,对象表示的位应分为两组:值位和填充位(后者不需要任何一个)。如果有 N 个值位,则每个位应表示 1 和 2 N-1之间的 2 的不同幂,以便该类型的对象应能够使用纯二进制表示表示从 0 到 2 N-1的值;这应称为值表示。未指定任何填充位的值。

对于有符号整数类型,对象表示的位应分为三组:值位、填充位和符号位。不需要任何填充位;signed char 不应有任何填充位。应该有一个符号位。作为值位的每个位应与相应无符号类型的对象表示中的相同位具有相同的值(如果有符号类型中有 M 个值位,无符号类型中有 N 个值位,则 M ≤ N)。如果符号位为零,则不应影响结果值。如果符号位为 1,则该值应通过以下方式之一进行修改:

— 符号位为 0 的对应值取反(符号和幅度);

— 符号位的值为 -(2 M )(二进制补码);

— 符号位的值为 −(2 M − 1 )(反码)。

其中哪一个适用是实现定义的,符号位为 1 且所有值位为零(对于前两个)或符号位和所有值位为 1(对于一个补码)的值是否是陷阱表示或正常值。在符号和幅度以及一个的补码的情况下,如果这个表示是一个正常值,它被称为负零。

总结

我认为这两个标准的意图是相同的。

  • charsigned charunsigned char让所有位参与该值

  • 其他整数类型可能具有不参与该值的填充位。它们中的错误位模式可能意味着无效值。

  • 解释是纯二进制表示,其定义在上面的 C11 引用中得到了扩展。

有两点可能不清楚:

  • 可以 -0(用于符号和幅度以及 _ones 的补码)是 C++ 中的陷阱值

  • 其中一个填充位可以是奇偶校验位吗(即,如果我们确保填充位不被修改,我们可以修改表示吗)

我会很保守,并认为两者都是肯定的。

于 2012-06-21T14:02:32.813 回答
2

是的,这是有保证的。

保证转换整数类型的所有字节/位以使该类型的实例具有零值 ( 0),如上述标准中的以下片段所述。


3.9.1/7 基本类型

整数类型的同义词是整数类型。整数类型的表示应使用纯二进制计数系统定义值。49

49使用二进制数字 0 和 1 的整数的位置表示,其中由连续位表示的值是相加的,从 1 开始,并乘以 2 的连续整数幂,除了可能具有最高位置的位。(改编自美国国家信息处理系统词典。)

于 2012-06-21T12:30:01.163 回答
2

没有。例如,标准中没有任何内容禁止基于偏差的表示,它只要求它是二进制的。

于 2013-02-23T21:25:11.933 回答
1

不,我不相信它实际上是有保证的,但它相当模糊。

如果曾经有一个 C++ 实现,其中所有位为零不是的表示,我会感到非常惊讶,但我相信这样的实现可能是符合要求的(尽管有悖常理)。0

让我们从考虑 C99 标准开始。(是的,我知道,这个问题是关于 C++ 的;请耐心等待。)它说无符号整数类型的对象表示的位分为两组:值位和填充位(不需要任何填充位,并且大多数实现都没有它们)。值位构成纯二进制表示;填充位对值没有贡献。填充位的某些组合可能会生成陷阱表示

有符号类型是相似的,只是增加了一个符号位。有符号类型可以使用符号和幅度二进制补码一个补码来表示——但同样,任何填充位都不会对值做出贡献,并且填充位的某些组合可以生成陷阱表示。

此描述不排除以下可能性,例如,比整数类型更宽的char 可能具有必须始终为 1 的单个填充位;如果它是 0,你有一个陷阱表示。或者,也许更合理的是,它可能有一个奇偶校验位。

C99标准发布后,第二次技术勘误增加了以下句子,同样出现在C11中。

对于任何整数类型,所有位都为零的对象表示应是该类型中值零的表示。

我要强调的是,这是作为规范文本而不是作为脚注添加的,这表明(但不证明)委员会成员认为 C99 标准中并未隐含该保证。

(C90 对整数类型的表示方式没有那么具体。它没有提到填充位、陷阱表示或二进制补码等。我认为它为实现提供了至少与 C99 一样多的灵活性。)

所以从 C99 TC2 开始,C 语言保证所有位为零是任何整数类型的零表示。在 C99 和 C90 中,没有说明该保证。

那是C。C++呢?

与 1990 年的 C 标准相比,2011 年的 C++ 标准似乎只提供了关于整数类型表示的稍微多一点的特殊性。它确实需要使用 2 的补码、1 的补码或有符号幅度来表示有符号类型。它还需要一个“纯二进制计数系统”。它没有提到“陷阱表示”,也没有讨论填充位,除非在位字段的上下文中。

因此,在 C90 和 TC2 之前的 C99 中,至少在理论上,全位零是整数类型的陷阱表示。C++ 标准对整数类型的要求与 C90 和 C99 的要求非常相似。它确实需要“纯二进制表示”,但我认为这适用于 C99 中的情况,仅适用于值位;尽管 C++ 没有提到填充位,但它并没有禁止它们。

同样,这主要是理论上的兴趣(因此是“语言律师”标签)。C 委员会随意强加要求所有位为零必须是零的表示,因为所有实现都已经满足它。几乎可以肯定,这同样适用于 C++。

于 2013-06-22T06:51:46.057 回答