将 int 的所有字节设置为(无符号字符)0,保证表示零
Set all bytes of int to (unsigned char)0, guaranteed to represent zero?
<小时 />这不是推荐的做法(也不是未定义的行为)的问题,而是关于 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 的补码,如果这个表示是正常值,则称为 负零。
总结
我认为这两个标准的意图是相同的。
-
char
,signed char
和unsigned 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++。
- 在 std::无符号字符的向量处存储 int 的十六进制表示形式
- 寻找一种更好的方法来表示无符号字符数组
- C++ CUDA:如何将字节表示为字符或字符集?
- 从 C++ 中的位表示形式初始化字符
- 十六进制 QString 表示为无符号字符数组
- C++字符串表示中将无符号字符数组转换为长(或长长)
- 如何转换由字符表示的十六进制值
- 如何将一个数字(大于8个字节)从字符阵列转换为其ASCII表示
- C/C++ 字符、无符号字符和有符号字符的基础表示形式
- 在 C++ 中用什么来表示 lambda 字符
- 为什么不能将 int(表示 ASCII 字符)转换为 std::字符串,而没有大括号环绕在 int 周围?
- 将二进制字符的字符串表示转换为字符串的最佳方法
- 关键字符的十进制表示
- 如何将无符号字符值表示为十六进制字符串
- 将 int 的所有字节设置为(无符号字符)0,保证表示零
- 分配字符缓冲区以保存浮点的文本表示形式
- 以十进制、八进制和十六进制表示法标识整数文本是否与转义字符中的整数文本相同
- 我想在窗口下使用 c++ 以某种基本方式表示西里尔字符
- 家庭作业:一组位中的快速操作(表示为字符数组)
- 如何获取特殊字符输入并存储在字符或字符串变量中?特殊字符表示©或 ž