我可以一口气检查一小撮布尔型吗?

Zeb*_*ish 28 c++ arrays casting boolean

有一个类似的问题在这里,但在这一问题的用户似乎有一个更大的阵列,或载体。如果我有:

bool boolArray[4];
Run Code Online (Sandbox Code Playgroud)

我想检查所有元素是否为假,我可以分别检查[0],[1],[2]和[3],也可以循环遍历。由于(据我所知)false应该具有值0,而除0以外的其他任何东西都为true,所以我想到了简单地做:

if ( *(int*) boolArray) { }
Run Code Online (Sandbox Code Playgroud)

这行得通,但是我意识到它依赖于布尔值是一个字节,整数是四个字节。如果我强制转换为(std :: uint32_t)可以,还是一个坏主意?我刚好在一个数组中有3或4个布尔值,并且想知道这是否安全,如果不是,那么是否有更好的方法可以做到。

另外,如果我最终得到超过4个布尔值,但少于8个布尔值,那么我可以使用std :: uint64_t或unsigned long long之类的东西做同样的事情吗?

Yks*_*nen 21

作为????? ??? 在评论中注意到,std::bitset这可能是无UB方式处理该问题的最佳方法。

std::bitset<4> boolArray {};
if(boolArray.any()) {
    //do the thing
}
Run Code Online (Sandbox Code Playgroud)

如果您要坚持使用数组,可以使用std::any_of,但这需要(可能是读者所特有的)用法functor,它仅返回其参数:

bool boolArray[4];
if(std::any_of(std::begin(boolArray), std::end(boolArray), [](bool b){return b;}) {
    //do the thing
}
Run Code Online (Sandbox Code Playgroud)

对4 bool进行类型调整int可能不是一个好主意-您不能确定每种类型的大小。它可能可以在大多数体系结构上运行,但是std::bitset可以保证在任何情况下都可以在任何地方运行。


Kev*_*vin 9

几个答案已经解释了好的选择,尤其是std::bitsetstd::any_of()。我写单独指出的是,除非你知道我们不这样做的东西,它是不是安全之间键入双关语bool,并int以这种方式,有以下几个原因:

  1. int 正如多个答案指出的那样,它可能不是四个字节。
  2. MM在注释中指出bool可能不是一个字节。我不知道这种情况曾经发生过的任何现实世界的体系结构,但是仍然是规范性的。它(可能)不能小于一个字节,除非编译器使用其内存模型进行一些非常精心的隐藏球装饰,而且多字节的布尔值似乎毫无用处。但是请注意,字节不必首先是8位。
  3. int可以有陷阱表示。也就是说,将某些位模式转换为时,导致未定义的行为是合法的int。这在现代体系结构上很少见,但可能出现在(例如)ia64或任何带符号零的系统上。
  4. 不管您是否需要担心上述任何一项,您的代码都违反了严格的别名规则因此,在布尔和int是完全独立的对象且不重叠生命周期的假设下编译器可以自由地对其进行“优化”。例如,编译器可能会确定初始化bool数组的代码为无效存储并消除它,因为在取消引用指针之前的某个时刻,布尔“必须具有”不再存在*。与寄存器重用和加载/存储重新排序有关的更复杂的情况也会出现。C ++标准明确允许所有这些愚蠢行为,该行为表示当您进行这种类型的修剪时,行为是不确定的。

您应该使用其他答案提供的替代解决方案之一。


*重用boolArray通过将其强制转换为int并存储一个整数所指向的内存是合法的(具有某些条件,特别是关于对齐),尽管如果您确实要这样做,那么如果要读取该内存则必须boolArray通过std::launder导致int稍后。无论如何,即使您不调用洗涤程序,编译器有权在看到读取内容后就假定您已完成此操作。