是否应在分配时将布尔值截断为 true 或 false
Should a boolean value be truncated to either true or false when assigned?
>我发现存储在布尔变量(顺便说一句 Visual-C++ 和 clang++)中的值存在差异,在存储的值既不真也不假的情况下(如果它以某种方式损坏),我不确定这是一个视觉C++错误,还是只是我应该忽略的 UB。
以以下示例为例:
#include <cstdint>
#include <iostream>
#include <string>
#include <limits>
bool inLimits(bool const v)
{
return (static_cast<std::int32_t>(v) >= static_cast<std::int32_t>(std::numeric_limits<bool>::min()) && static_cast<std::int32_t>(v) <= static_cast<std::int32_t>(std::numeric_limits<bool>::max()));
}
int main()
{
bool b{ false };
bool const* const pb = reinterpret_cast<bool const*>(&b);
std::uint8_t * const pi = reinterpret_cast<std::uint8_t*>(&b);
std::cout << "b: " << b << " pb: " << (*pb) << " pi: " << std::to_string(*pi) << std::endl;
std::cout << "b is " << (inLimits(b) ? "" : "not ") << "in numeric limits for a bool" << std::endl;
*pi = 3; // Simulate a bad cast during boolean creation
bool const b2{ b };
bool const b3{ *pb };
std::cout << "b: " << b << " pb: " << (*pb) << " pi: " << std::to_string(*pi) << std::endl;
std::cout << "b2: " << b2 << " b3: " << b3 << std::endl;
std::cout << "b is " << (inLimits(b) ? "" : "not ") << "in numeric limits for a bool" << std::endl;
std::cout << "b2 is " << (inLimits(b2) ? "" : "not ") << "in numeric limits for a bool" << std::endl;
std::cout << "b3 is " << (inLimits(b3) ? "" : "not ") << "in numeric limits for a bool" << std::endl;
return 0;
}
这是视觉C++的输出
b: 0 pb: 0 pi: 0
b is in numeric limits for a bool
b: 3 pb: 3 pi: 3
b2: 3 b3: 3
b is not in numeric limits for a bool
b2 is not in numeric limits for a bool
b3 is not in numeric limits for a bool
这是 clang++ 的输出
b: 0 pb: 0 pi: 0
b is in numeric limits for a bool
b: 1 pb: 1 pi: 3
b2: 1 b3: 1
b is in numeric limits for a bool
b2 is in numeric limits for a bool
b3 is in numeric limits for a bool
看起来在按值构造新的布尔值时,以及当它与流运算符一起使用时,clang++ 中有一个限制检查。
我应该忽略这一点,还是只有视觉C++才有的错误? 谢谢!
编辑:对于那些不了解示例目的的人来说,它只是一个展示,用于"模拟"内存损坏或代码另一部分中的错误,这些错误导致布尔值被初始化为真或假以外的其他东西,无论布尔值的二进制表示如何。
(我想知道我是否必须使用断言保护我的代码免受其他地方的不当使用,但前提是此行为不是 UB)
第二次编辑:添加了numeric_limits代码。
"在存储的值既不真也不假的情况下">
你为什么会这样认为?C++ 不限制bool
的二进制表示。在某些编译器上,true
可以用00000011
表示,而其他编译器可以选择将false
表示为00000011
。
但事实上,GCC 和 MSVC 都没有将该位模式用于任一bool
值。这使得它确实是未定义的行为。UB永远不能成为编译器错误。错误是指实现无法正常工作,但 UB 明确表示任何实际行为都是可以接受的。
该标准没有指定bool
的值表示是什么。编译器可以自由地制定自己的规范。
您的证据表明,VC++ 要求true
仅表示为 LSB 集,而 clang++ 允许true
任何非零表示。
对于VC++,您的代码会导致行bool const b2{ b };
上未定义的行为,特别是当它尝试从b
中读取值时。存储中为b
设置的位不对应于b
的值,并且标准没有定义在这种情况下会发生什么,因此它是未定义的行为。
当未定义的行为发生时,没有任何保证;程序的所有输出都是毫无意义的。您无法根据在此点之后(甚至实际上在它之前)出现的输出语句来推断任何内容。
由于我真的没有在标准中找到有关从指针到布尔(或等效)的转换信息C++(如果定义了这些用法),我不愿意将其作为答案发布。但是,再三考虑,我不妨发布它 - 它可能会被其他人详细说明。
首先,C++14标准将bool
定义为:
[基础.基础]
- 布尔类型的值为真或假。[注意:没有有符号、无符号、短布尔值或长布尔值类型或值。布尔类型的值参与积分促销 (4.5)
由于它参与整体促销,因此为其定义了以下促销:
[会议舞会]
布尔类型的 prvalue
- 可以转换为 int 类型的 prvalue,false 变为零,true 变为 1。
并且,由于您正在使用std::ostream::operator<<
进行打印,因此对于bool
,它的定义如下:
[ostream.inserters.arithmetic]
- 类num_get<>和num_put<>处理与区域设置相关的数字格式设置和分析。
由于它使用num_put<>
进行实际输出,因此与bool
输出相关的代码片段定义为:
[facet.num.put.virtuals]
- If (str.flags() & ios_base::boolalpha) == 0 返回 do_put(out, str, fill, (int)val)
由于您未在所示示例中使用boolalpha
- 因此应应用典型的整体促销规则(如上所述)。
此外,我仍然无法解释为什么std::to_string(*pi)
*pi = 3
之后仍然3
两种情况下打印,但它可能以某种方式与以下方面有关:
[重新诠释]
- [注意:reinterpret_cast执行的映射可能会或可能不会产生与原始值不同的表示形式。
不确定这是否有帮助,但 g++ 表现出与 Visual-C++ 相同的行为。
这是我得到的输出:
B: 0 PB: 0圆周率: 0 B: 3 铅: 3 圆周率: 3 b2: 3 b3: 3
据我了解(我是 c++ 编译器专家),reinterpret_cast
指示编译器将位集合视为新类型。因此,当您告诉编译器将布尔值的地址重新解释为 8 位整数时,它实际上是将原始布尔值转换为 8 位整数(如果这有意义的话)。
因此,如果我的解释是正确的(事实并非如此),也许这是 clang++ 中的一个"错误",而不是 Visual 或 g++。 编译器之间reinterpret_cast
不是很好支持,因此在决定使用哪个时,如果出于某种原因有必要,则此行为绝对值得注意。
编辑:
我刚刚意识到这并不能解释为什么 b2 和 b3 也是 3(非布尔值)。我不认为将新布尔值也视为 8 位整数是有意义的,无论reinterpret_cast
如何,所以从一个有 1 个代表的人那里得到它的价值:)
- Arduino-C++ bool 不会从 false 变为 true
- 如何使用boost定义布尔类,可能的值应该是TRUE或FALSE?
- C++如果使用 lambda 表达式的语句返回 true,但输出来自 false,为什么
- MFC 的 OnInit() 函数中的返回 true 和返回 false 有什么区别
- std::is_array 当它应该返回 false 时返回 true
- 如果BOOL仅从false到true一次,我可以避免锁定布尔
- `如果constexpr(false)`始终评估为true
- 是否应在分配时将布尔值截断为 true 或 false
- 我想返回 True/False 关于值是否在一组值中
- 尝试将字符串变量转换为布尔值会导致 "true" 和 "false" 都等于 0
- C 程序,用于分级多个True或False测试
- true/false功能如果存在总和
- 查找n连续字符的函数返回true/false
- 我正在尝试创建一个函数,如果一个元素在向量中,则返回 true/false,但我收到错误
- 将 true/false 分配给 std::string:这是怎么回事?
- 如果数据类型为整数值或双数值,则当c++返回true/false时
- 如果某个条件语句中的某些内容导致该条件语句不再为true/false,则该语句是否停止执行
- bool递归函数中的true/false优先级
- c++ bool返回0 1而不是true false
- While循环为true false,不加增量