将 int 的所有字节设置为(无符号字符)0,保证表示零

Set all bytes of int to (unsigned char)0, guaranteed to represent zero?

本文关键字:字符 表示 无符号 int 字节 设置      更新时间:2023-10-16

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

<小时 />

问题

在下面的代码片段中,if-语句使用的表达式是否保证在 c++11 中计算为 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]

基本

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

C++ 11

我认为相关的部分是

3.9.1/1 英寸 C++11

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

连同 3.9.1/7

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

C11

6.2.6.2 非常明确

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

对于有符号整数类型,对象表示的位应分为三个 组:值位、填充位和符号位。不需要任何填充位; 签名字符不得有任何填充位。应正好有一个符号位。 作为值位的每个位应与对象中的相同位具有相同的值 表示相应的无符号类型(如果有符号中有 M 值位 类型和无符号类型中的 N,然后是 M ≤ N)。如果符号位为零,则不会影响结果值。如果符号位为 1,则应在其中一个 以下方式:

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

— 符号位的值为 −(2M) (二的补码);

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

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

总结

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

  • charsigned charunsigned char都有位参与该值

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

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

有两件事可能不清楚:

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

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

我会很保守,并假设两者都是。

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

是的,这是有保证的。

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


3.9.1/7 基本类型

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

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

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

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

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

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

此说明不排除以下可能性:例如,大于 char 的整数类型可能具有必须始终为 1 的单个填充位;如果为 0,则具有陷印表示形式。或者,也许更合理的是,它可能有一个奇怪的奇偶校验位。

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

对于任何整数类型,所有位所在的对象表示形式 零应表示该类型中的值零。

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

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

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

那是C。C++呢?

2011 C++ 标准似乎只提供了与旧的 1990 C 标准相比稍微更具体的整数类型表示。它确实要求有符号类型使用 2 的补码、1 的补码或有符号量级来表示。它还需要一个"纯二进制数字系统"。它没有提到"陷阱表示",也没有讨论填充位,除非在位字段的上下文中。

因此,在 C90 和 TC2 之前的 C99 中,至少在理论上有可能让所有位零成为整数类型的陷阱表示。C++标准对整数类型的要求与 C90 和 C99 的要求非常相似。它确实需要"纯二进制表示",但我认为这仅适用于值位,就像在 C99 中一样;虽然C++没有提到填充位,但它并没有禁止它们。

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