布尔值是否应在分配时被截断为true或false?

时间:2017-04-12 13:49:09

标签: c++ visual-c++ boolean clang++ bounds

我发现存储在bool变量(btw Visual-C ++和clang ++)中的值存在差异,如果存储的值既不是true也不是false(如果它以某种方式被破坏),我和#39;我不确定它是否是Visual-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;
}

这是Visual-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 ++中存在限制检查。

我应该忽略这一点,还是仅仅是Visual-C ++的错误? 谢谢!

修改 对于那些不了解样本目的的人来说,它只是一个展示模拟&#34;模拟&#34;内存损坏或代码的另一部分中的错误导致布尔值初始化为除了true或false之外的其他内容,无论bool的二进制表示形式如何。

(我想知道我是否必须使用断言保护我的代码在其他地方不正当使用,但仅当此行为不是UB时)

第二次修改 添加了numeric_limits代码。

4 个答案:

答案 0 :(得分:3)

&#34;在存储值既不是真也不是假的情况下&#34;

为什么你认为是这样的? C ++不限制bool的二进制表示。在某些编译器上,true可以由00000011表示,其他编译器可以选择将false表示为00000011

但实际上,GCC和MSVC都没有对bool值使用该位模式。这使得它确实是未定义的行为。 UB 永远不会成为编译器错误。错误是实现不能正常工作的地方,但UB特别意味着任何实际行为都是可以接受的。

答案 1 :(得分:2)

标准没有规定bool的值表示是什么。编译器可以自由制定自己的规范。

您的证据表明VC ++要求true仅表示为LSB集,而clang ++允许任何非零表示形式为true

对于VC ++,您的代码会在行bool const b2{ b };上导致未定义的行为,特别是当它尝试从b读取值时。在b的存储中设置的位不对应b的值,并且标准不定义在这种情况下发生的情况,因此它是未定义的行为。

当未定义的行为发生时,没有任何保证;程序的所有输出都没有意义。您无法根据此点之后(或实际上甚至在它之前)出现的输出语句推断出任何内容。

答案 2 :(得分:1)

由于我没有,真的,在C ++标准中找到有关指针到bool(或等效)的转换的信息(如果定义了这些的使用),我不愿意将此作为答案发布。但是,在第二个想法,我也可以发布它 - 它可能会被其他人详细阐述。

首先,C ++ 14标准将bool定义为:

  

[basic.fundamental]

     
      
  1. bool类型的值为true或false。 [注意:没有signed,unsigned,short或long bool类型或值。 - 尾注] bool类型的值参与整体促销(4.5)
  2.   

由于它参与了整体促销活动,因此为其定义了以下促销活动:

  

[conv.prom]

     
      
  1. bool类型的prvalue可以转换为int类型的prvalue,false变为0,true变为1。
  2.   

而且,由于您使用std::ostream::operator<<打印bool,因此定义如下:

  

[ostream.inserters.arithmetic]

     
      
  1. 类num_get&lt;&gt;和num_put&lt;&gt;处理依赖于区域设置的数字格式和解析。
  2.   

由于它使用num_put<>作为实际输出,因此与bool输出相关的片段定义为:

  

[facet.num.put.virtuals]

     
      
  1. if(str.flags()&amp; ios_base :: boolalpha)== 0返回do_put(out,str,fill,(int)val)
  2.   

由于您未在示例中使用boolalpha,因此应采用典型的整数提升规则(如上所述)。

此外,我仍然无法解释为什么std::to_string(*pi)*pi = 3仍然打印3两种情况下,但它可能在某种程度上与以下内容相关:

  

[expr.reinterpret.cast]

     
      
  1. [注意:reinterpret_cast执行的映射可能会或可能不会产生与原始值不同的表示.-尾注]
  2.   

答案 3 :(得分:0)

不确定这是否有帮助,但g ++表现出与Visual-C ++相同的行为。

这是我得到的输出:

b: 0 pb: 0 pi: 0
b: 3 pb: 3 pi: 3
b2: 3 b3: 3

根据我的理解(我是关于c ++编译器的专家),reinterpret_cast指示编译器将位集合视为新类型。因此,当您告诉编译器将布尔值的地址重新解释为8位整数时,它实际上也是将原始布尔值转换为8位整数(如果这是有意义的话)。 / p>

因此,如果我的解释是正确的(它不是),那么这可能是一个&#34;错误&#34;在clang ++中,而不是Visual或g ++。 reinterpret_cast在编译器之间得不到很好的支持,因此在决定使用哪种行为时,这种行为绝对值得注意,如果出于某种原因这是必要的。

编辑:

我刚刚意识到这并不能解释为什么b2和b3也是3(非布尔)。我不会想象将新的布尔值作为8位整数处理也是有意义的,无论reinterpret_cast如何,所以请将其作为1个代表的人的价值。 :)