【问题标题】:behavior of bool with non-boolean operators带有非布尔运算符的布尔行为
【发布时间】:2010-11-20 16:18:43
【问题描述】:

我真正想要的是 ||= 运算符。

old_value = old_value || possible_new_value;
old_value ||= possible_new_value;

第二行是编译器错误(c++ 没有 ||= 运算符)。

那么我还有哪些其他选择?

old_value += possible_new_value;
old_value |= possible_new_value;

当我谈到这个主题时,bool 与其他非布尔运算符的行为如何?

-
-=
&
&=
...

我可以凭经验验证这些,但我最感兴趣的是标准所说的内容。

【问题讨论】:

    标签: c++ coding-style standards-compliance


    【解决方案1】:

    不要将|=&= 与布尔值一起使用。他们可能大部分时间都在工作,但它仍然是错误的。通常 bool 类型只是一个美化的 int 或 char。在我使用过的旧代码中,BOOL 只是类型定义为 int 或 char。在这些情况下,如果以某种方式对位进行了操作,您可能会得到错误的答案(例如,1&2 为 0(假))。而且我不确定,但我认为按位运算符的结果将是一个 int,即使对于 bool 也是如此。

    【讨论】:

    • 如果两个变量都声明为 'bool',在什么情况下(除了损坏的编译器 - 或非标准的,即准标准编译器)它们会出错?
    • 如果有任何东西作为 void* 或其他东西传递,并且您有一个使用该类型作为 int 的 API,您不能保证它们总是使用“1”表示真,而不是任何其他非零整数。
    • @Kip:你说“如果变量不是bool,那么也许所有的地狱都会崩溃”,这与我的起始位置“如果两个变量都声明为@987654326 @"。但是,我知道您来自哪里......如果变量不是严格的布尔值,那么运算符的行为是不可预测的,因为值的范围是不可预测的。回到我的实际问题 - 如果两个变量实际上都是 bool 类型,那么表达式会出错吗?
    • @kip:您是说运算符不应该与布尔值一起使用,因为它们不能与非布尔值一起使用?这似乎有点倒退。
    • 在 C++ 中,这不可能发生,因为 bool 是一个自己的基本类型。这不是 typedef。
    【解决方案2】:
    if (!old_value)
        old_value = possible_new_value;
    

    这是原始条件的直接等价物。它可能会生成更简单的代码,因为它不会总是分配给 old_value - 但我不希望在大型程序中可以轻松测量性能差异。

    【讨论】:

      【解决方案3】:

      一个区别是,|| 等逻辑运算符保证了求值顺序并提供了短路,而按位和算术运算符则不能。

      我相信编译器会通过将布尔值转换为数值 (0, 1) 应用运算符并转换回来来处理非逻辑运算符。这些转换是由标准严格定义的,例如:

      算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool 类型的右值。零值、空指针值或空成员指针值转换为 false 任何其他值都转换为 true。

      【讨论】:

        【解决方案4】:

        你能用三元运算符吗?

        old_value = !old_value ? possible_new_value : old_value;

        【讨论】:

        • 为什么它比较短的old_value = old_value || new_value; 更受欢迎?
        • 似乎我读错了问题:)没有理由这样做而不是old_value = old_value || new_value;,尤其是因为后者更具可读性。
        【解决方案5】:

        讨厌的宏骇客:

        #define UPDATE(x) x = x
        
        UPDATE(old_value) || possible_new_value;
        

        但我完全不推荐这个。出于多种原因,像这样的宏是一个非常糟糕的主意。

        一个更健全的功能,但没有短路:

        bool set_or(bool &old, bool value) {
          return (old = old || value);
        }
        
        ...
        
        bool v = false;
        set_or(v, true);
        

        【讨论】:

        • 当然,这仅在 x 是变量时有效,并且仅在 x 没有以左值结尾时明显失败,并且关键取决于在宏中构建一半和一半的表达式.呜呜呜。
        • 如果possible_new_value 的评估有副作用,此宏将失败。
        • 如果失败取决于||= 的正确语义应该是什么。我不确定是否会在那里进行短路。
        【解决方案6】:

        根据 4.7(整数转换)第 4 段,“如果目标类型是 bool,请参见 4.12。如果源类型是 bool,则值 false 将转换为零,值 @987654324 @ 转换为一。”在 4.12 中,“算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool 类型的右值。零值、空指针值或空成员指针值转换为 false;任何其他值都将转换为 true。"

        在不允许使用bool 操作数但允许使用整数操作数的上下文中,bool 将被转换为整数类型。当整数结果存储在bool变量中时,它将被转换为bool

        因此,您将能够将 + 和 * 用作布尔值或与与,并且您可以使用 |并且。你不能混合它们,因为 (bool1 + bool2) & bool3 将产生 false 如果所有三个变量都是 true。 ((1 + 1) & 1 是 2 & 1,也就是 0,否则为假。)

        请记住 |和 ||即使在这里也不一样。 |将评估双方,然后评估按位或。 ||将评估第一个操作数,然后只有当它为假时才会评估第二个。

        我不打算在这里讨论风格问题,但如果我做了类似的事情,我一定会发表评论,以便人们知道我在做什么以及为什么。

        【讨论】:

        • +1 用于引用标准(并回答问题),同时还添加关于样式的评论
        【解决方案7】:

        标准说:

        4.5-4“综合促销”

        bool 类型的右值可以是 转换为 int 类型的右值, 假变成零和真 合而为一。

        5.17-7“赋值运算符”

        表达式的行为 形式 E1 op= E2 等价于 E1 = E1 op E2 除了 E1 被评估 只有一次。在 += 和 -= 中,E1 应 要么有算术类型,要么是 指向可能 cvqualified 的指针 完全定义的对象类型。在所有 其他情况,E1 应有算术 输入。

        4.12-1“布尔转换”

        算术、枚举、 指针,或指向成员类型的指针可以 被转换为类型的右值 布尔。零值,空指针 值,或空成员指针值是 转换为假;任何其他值是 转换为真。

        所以这意味着

        b1 += b2
        

        其中 b1 和 b2 是布尔值将等价于

        b1 = b1 + b2
        

        并且 b1 和 b2 将被提升为 0/1 整数,然后根据除 0 以外的任何值都为真的规则转换回布尔值。

        所以真值表是

        真假 真的 真的 真的 假 真 假

        所以 += 实际上根据标准作为 ||= 工作。但是,这可能会让其他程序员感到困惑,所以我还是会避免它。

        【讨论】:

        • +1 用于引用标准、+= 的明确细分以及避免 += 的建议。
        【解决方案8】:

        我相信标准明确将真假定义为 1 和 0,因此您可以安全地对 bool 值使用位运算符。在另一个上下文中可能被隐式视为布尔值的其他类型应显式转换以使其可靠地工作。

        我看到微软的编译器每次执行此操作时都会生成一个丑陋的警告,因为它认为将 int 结果隐式转换回 bool 存在危险。

        【讨论】:

          猜你喜欢
          • 2020-08-22
          • 2022-01-01
          • 2011-11-13
          • 1970-01-01
          • 2023-03-12
          • 1970-01-01
          • 2011-09-27
          • 2011-03-27
          相关资源
          最近更新 更多