在布尔中写入0或1以外的值是UB吗?如果是,它们如何比较
Is it UB to write values other than 0 or 1 in a bool? If yes, how do they compare?
考虑下面的程序。
所有比较与最近的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
或其签名或未签名的表亲(,但是将这些值映射到 true
和 false
仍然未指定。
写作任何 integer noteger值通过bool
以外的其他类型不确定的指针到bool
中行为,因为这些行为可能与编译器的类型表示不匹配。是的,编写0或1以外的其他内容绝对会破坏事物:编译器通常依赖于布尔true
的确切内部表示。
但是bool b = 3
很好,并且仅将b
设置为true
(从整数类型转换为bool
的规则是,任何非零值将变为 true
,零变为 false
(。
可以将true
和false
以外的值分配给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的值是
true
或false
。
标准不要求将true
表示为1
和/或false
表示为0
。实施可以选择最适合其需求的表示形式。
标准继续说明bool
类型的值:
以该国际标准描述为"未定义"的方式,使用
。bool
值,例如通过检查非初始化自动对象的价值,可能会导致它的行为,好像它既不是true
也不是false
。
将值char(1)
或char(0)
存储在其内存位置中间接地保证该值将被正确转换为true
/false
。由于Theose值可能不代表实施中的true
或false
,因此访问这些值将导致不确定的行为。
通常,将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
。可能没有想到。
- 如果相同的数字重复,如何比较流中的数字
- 如果要求比较器是严格的总排序,而不仅仅是严格的弱排序,C++标准算法会更快吗?
- 我如何将一个变量与另一个变量进行比较,例如我想如果(var1 > var2 x 1),然后执行此 c++
- 如果调用 RtlSetProcessIsCritical,将使用 lstrcmpW 将命令行与值进行比较将使程序崩溃
- 如果堆栈在数字较低的地址增长,为什么指针比较会逆转这种情况?
- 根据下面的作者,如果两个指针指向不同的数组,则比较的第一个版本将未定义
- 自定义迭代器:如果 a 和 b 的行为不同,如何正确处理距离计算和相等比较
- 在布尔中写入0或1以外的值是UB吗?如果是,它们如何比较
- 如何将向量一的所有元素与向量二进行比较,如果存在最大元素,则将向量二的所有元素与向量三进行比较?
- 如果我在与字符进行比较之前没有明确将 int 转换为字符,这有关系吗?
- 如何将一个数组的每个元素与另一个元素进行比较(如果存在),然后打印是,否则否
- 如果和比较顺序
- 如果我为浮点数定义了自定义比较函数,std::sort 会正常工作吗?
- Clang和GCC与MSVC和ICC的比较:如果复制/移动省略也适用,那么在复制/移动构造函数中是否需要静态断言
- c ++比较std::string将无法工作,如果我不使用Code::Blocks但cygwin编译
- C++ 如果其他链和嵌套用于变量比较
- 原子比较,如果更少,则有条件地减去
- 无法获得如果(数字== 1)比较工作
- 如果比较函数不是运算符<,为什么std::sort会崩溃;
- 如果您意外地使用布尔运算符 (||, &&) 比较常量,则发出警告