假设我有一些遗留代码,除非发现错误,否则无法更改,并且它包含以下代码:
bool data[32];
memset(data, 0, sizeof(data));
这是将数组中的所有bool
设置为false
值的安全方法吗?
更一般地说,memset
bool
到0
是否可以安全地使其值false
?
是否可以保证适用于所有编译器?或者我是否要求修复?
答案 0 :(得分:24)
法律是否有保障?否强>
C ++没有提及bool
值的表示。
实际现实是否有保障?是强>
我的意思是,如果你希望找到一个不代表布尔值false
的C ++实现作为一个零序列,我祝你好运。鉴于false
必须隐式转换为0
,而true
必须隐式转换为1
,0
必须隐式转换为false
,并且非 - 0
必须隐式转换为true
......好吧,你以任何其他方式实施它都是愚蠢的。
这是否意味着它安全"是你的决定。
我通常不会这样说,但如果我处于你的情况,我会乐意让这张幻灯片。如果您真的担心,可以在可安装实际项目之前,为可分发项添加测试可执行文件,以验证每个目标平台的前提条件。
答案 1 :(得分:9)
不。这不安全(或更具体地说是便携式)。但是,由于您的典型实现将:
,它可能正常工作memset()
可以处理的元素数组。但是,最佳实践将指示使用bool data[32] = {false}
- 此外,这可能会使编译器在内部以不同方式表示结构 - 因为使用memset()
可能会导致生成32字节的值数组而不是比如说一个4字节,它可以很好地适应你的平均CPU寄存器。
答案 2 :(得分:7)
从3.9.1 / 7:
类型bool,char,char16_t,char32_t,wchar_t,以及签名和 无符号整数类型统称为整数类型。一个 整数类型的同义词是整数类型。的陈述 整数类型应使用纯二进制计数定义值 系统
鉴于此,我无法看到bool
的任何可能的实现都不能表示为全0位的错误。
答案 3 :(得分:7)
我认为这个没有说明,尽管false
的基本表示似乎可能都是零。 Boost.Container relies on this as well(强调我的):
Boost.Container使用带有零值的std :: memset来初始化一些 在大多数平台中,这种初始化产生了所需的类型 值初始化,提高了性能。
遵循C11标准,Boost.Container假设为任何 整数类型,所有位均为零的对象表示 应该表示该类型的零值。的由于 _Bool / wchar_t / char16_t / char32_t也是C中的整数类型,它认为所有C ++整数类型都可以通过std :: memset初始化。
他们指出这个C11引用的理由实际上来自C99缺陷:defect 263: all-zero bits representations其中添加了以下内容:
对于任何整数类型,所有位都是的对象表示 零应该是该类型中零值的表示。
那么这里的问题是假设正确,C和C ++之间的整数兼容的底层对象表示是什么?
Resolving the difference between C and C++ with regards to object representation of integers提案在某种程度上试图回答这个问题,据我所知,这个问题没有得到解决。我在标准草案中找不到确凿的证据。我们有几种情况,它明确地链接到C标准的类型。第3.9.1
[basic.fundamental] 部分说:
[...]有符号和无符号整数类型应满足 C标准中给出的约束,第5.2.4.2.1节。
和3.9
[basic.types] 说:
类型T的对象的对象表示是N的序列 由类型T的对象占用的unsigned char对象,其中N等于 的sizeof(T)。对象的值表示是位集 保持类型T的值。对于简单的可复制类型,值 表示是对象表示中的一组位 确定一个值,它是一个离散元素 实现定义的值集。 44
其中脚注44(不是规范)说:
意图是C ++的内存模型兼容 ISO / IEC 9899编程语言C.
标准草案在指定 bool 的基础表示时所用的最远位于3.9.1
部分:
类型bool,char,char16_t,char32_t,wchar_t,以及签名和 无符号整数类型统称为整数类型 整数类型的同义词是整数类型。的陈述 整数类型应使用纯二进制计数定义值 system.51 [例如:本国际标准允许2 补码,1的补码和有符号的幅度表示 整体类型。 - 例子]
该部分还说:
bool类型的值为true或false。
但我们所知道的true
和false
是:
布尔文字是关键字false和true。这样的文字 是prvalues并且有类型bool。
我们知道它们可以转换为0
和1
:
bool类型的prvalue可以转换为int类型的prvalue 假成为零,真正成为一个。
但是这让我们更接近于潜在的表现形式。
据我所知,除了填充位之外,标准引用实际底层位值的唯一位置是通过defect report 1796: Is all-bits-zero for null characters a meaningful requirement? 删除的:
不清楚便携式程序是否可以检查表示的位;相反,它似乎仅限于检查与值表示相对应的数字位(3.9.1 [basic.fundamental]第1段)。要求空字符值比较等于0或' \ 0'可能更合适。而不是指定表示的位模式。
有更多defect reports处理标准中的差距,关于值和对象表示之间的差异和差异。
实际上,我希望这会起作用,我不会认为它是安全的,因为我们无法在标准中指出这一点。你是否需要改变它,不清楚,你显然需要进行一些非平凡的权衡。因此,假设它现在有效,我们认为它可能会打破各种编译器的未来版本,这是未知的。