在布尔中写入0或1以外的值是UB吗?如果是,它们如何比较

Is it UB to write values other than 0 or 1 in a bool? If yes, how do they compare?

本文关键字:如果 比较 何比较 UB 布尔中      更新时间:2023-10-16

考虑下面的程序。

所有比较与最近的GCC都是正确的,但只有值1与Visual Studio Commandline编译器诉19.16.27031.1相等,x86。

我相信,通常可以通过字符指针写入豆荚。但是标准中是否有关于将有趣值写入布尔变量的措辞?如果允许,是否有关于比较中的行为的措辞?

#include <iostream>
using namespace std;
void f()
{
   if(sizeof(bool) != 1)
   {
      cout << "sizeof(bool) != 1n";
      return;
   }
  bool b;
  *(char *)&b = 1;
  if(b == true) { cout << (int) *(char *)&b  << " is truen"; }
  *(char *)&b = 2;
  if(b == true) { cout << (int) *(char *)&b  << " is truen"; }
  *(char *)&b = 3;
  if(b == true) { cout << (int) *(char *)&b  << " is truen"; }
}
int main()
{
    f();
}

P.S。GCC 8.3使用test指令有效检查非零,而GCC 9.1显式比较1,仅使该比较正确。也许此Godbolt链接起作用。

no。这是不可行的。

在bool中写任意数据很大(请参阅严格的别名规则?(,与C 标准相似,是否允许非初始化的布尔崩溃程序?

*(char *)&b = 2;

这种类型的punning hack Inde uncoke ub。根据您对bool的编译器实施及其允许进行的优化,您可以让恶魔从鼻子上飞来。

考虑:

bool b;
b = char{2};     // 1
(char&)b = 2;    // 2
*(char*)&b = 2;  // 3

在这里,第2行和第3行具有相同的含义,但是1具有不同的含义。在第1行中,由于分配给bool对象的值非零,因此结果保证为true。但是,在第2和3行中,bool对象的对象表示直接写入。

通过char类型的LVALUE写入任何非const类型的对象确实是合法的,但是:

在C 17中,该标准未指定bool对象的表示。bool类型可能具有填充位,甚至可能大于char。因此,任何以这种方式直接写入bool值的尝试都可能产生无效的(或"陷阱"(对象表示,这意味着随后读取该值将产生未定义的行为。实施可能(但标准不需要(定义bool对象的表示。

在C 20中,我的理解是,多亏了P1236R1,不再有任何陷阱表示,但是bool的表示仍未完全指定。bool对象可能仍然大于char,因此,如果仅写入其第一个字节,它仍然可以包含不确定的值,在访问时会产生UB。如果bool是1个字节(可能是1个字节(,则结果未指定---必须产生基础类型的某些有效值(很可能是char或其签名或未签名的表亲(,但是将这些值映射到 truefalse仍然未指定。

写作任何 integer noteger值通过bool以外的其他类型不确定的指针到bool中行为,因为这些行为可能与编译器的类型表示不匹配。是的,编写0或1以外的其他内容绝对会破坏事物:编译器通常依赖于布尔true的确切内部表示。

但是bool b = 3很好,并且仅将b设置为true(从整数类型转换为bool的规则是,任何非零值将变为 true,零变为 false(。

可以将truefalse以外的值分配给bool类型的变量。

通过使用标准转换序列为true/false,将RHS转换为bool

但是,您要做的是不可行的。

*(char *)&b = 2;  // Not OK
*(char *)&b = 3;  // Not OK

甚至通过使用该机制分配1和0是不正确的。

*(char *)&b = 1;  // Not OK
*(char *)&b = 0;  // Not OK

以下语句还可以。

b = 2; // OK
b = 3; // OK

更新,响应OP的评论。

来自标准/basic.types#basic.fundamental-6:

类型Bool的值是truefalse

标准不要求将true表示为1和/或false表示为0。实施可以选择最适合其需求的表示形式。

标准继续说明bool类型的值:

以该国际标准描述为"未定义"的方式,使用bool值,例如通过检查非初始化自动对象的价值,可能会导致它的行为,好像它既不是true也不是false

将值char(1)char(0)存储在其内存位置中间接地保证该值将被正确转换为true/false。由于Theose值可能不代表实施中的truefalse,因此访问这些值将导致不确定的行为。

通常,将0或1以外的值分配给bool是完美的:

7.3.14布尔转换 [Cons.Bool] 1算术,未上的枚举,指针或指针到成员类型的序幕可以转换为类型bool的prvalue。零值,空指针值或NULL成员指针值将转换为false;任何其他值都转换为true。

,但您的演员表完全是另一个问题。

请谨慎以为可以通过指针写入其他东西写给类型。您可以获得非常令人惊讶的结果,并且允许优化器假设某些此类事情未完成。我不知道所有规则,但是优化器并不总是按照指示来遵循不同类型的写作(在存在不确定的行为的情况下可以做各种事情!(,但是请注意,这样的代码:

bool f()
{
    bool a = true;
    bool b = true;
    *reinterpret_cast<char*>(&a) = 1;
    *reinterpret_cast<char*>(&b) = 2;
    return a == b;
}

live:https://godbolt.org/z/hjnusi

具有优化:G : -> true(但实际上是2(clang: -> false

main() {
    std::cout << f() << "n";  // g++ prints 2!!!
}

虽然f((返回一个布尔,但G 实际上在此处的Main中打印出2。可能没有想到。

相关文章: