是否有任何理由不在C ++中使用按位运算符&,|和^作为“bool”值?

我有时会遇到两个条件中只有一个是真的(XOR)的情况,所以我只是将^运算符抛出到条件表达式中。 我有时也希望评估条件的所有部分是否结果是真的(而不是短路),所以我使用&和|。 我有时也需要累积布尔值,而且&=和| =非常有用。

这样做的时候我已经有了一些眉毛,但代码仍然比其他方面更有意义和更清晰。 是否有任何理由不将这些用于布尔? 是否有任何现代编译器会给出不好的结果?

===============>>#1 票数:49 已采纳

|| &&是布尔运算符,内置函数保证返回truefalse 没有其他的。

| &^是按位运算符。 当你操作的数字域只有1和0时,它们完全相同,但是如果你的布尔值不是严格的1和0 - 就像C语言一样 - 你可能最终会遇到一些行为你不想要。 例如:

BOOL two = 2;
BOOL one = 1;
BOOL and = two & one;   //and = 0
BOOL cand = two && one; //cand = 1

但是,在C ++中, bool类型只能保证为truefalse (分别隐式转换为10 ),因此不需要担心这种立场,而是人们不习惯在代码中看到这样的东西对于不这样做是一个很好的论据。 只要说b = b && x可以了。

===============>>#2 票数:26

两个主要原因。 总之,要仔细考虑; 可能有一个很好的理由,但是如果你的评论中有非常明确的,因为它可能很脆弱,正如你自己说的那样,人们通常不习惯看到这样的代码。

按位xor!=逻辑xor(0和1除外)

首先,如果您使用的值不是falsetrue (或01 ,作为整数),则^运算符可以引入不等于逻辑xor的行为。 例如:

int one = 1;
int two = 2;

// bitwise xor
if (one ^ two)
{
  // executes because expression = 3 and any non-zero integer evaluates to true
}

// logical xor; more correctly would be coded as
//   if (bool(one) != bool(two))
// but spelled out to be explicit in the context of the problem
if ((one && !two) || (!one && two))
{
  // does not execute b/c expression = ((true && false) || (false && true))
  // which evaluates to false
}

感谢用户@Patrick首先表达了这一点。

运作顺序

第二, | & ,和^ ,作为按位运算符,不要短路。 此外,在单个语句中链接在一起的多个按位运算符 - 即使使用明确的括号 - 也可以通过优化编译器进行重新排序,因为所有3个操作通常都是可交换的。 如果操作的顺序很重要,这一点很重要。

换一种说法

bool result = true;
result = result && a() && b();
// will not call a() if result false, will not call b() if result or a() false

并不总是给出相同的结果(或结束状态)

bool result = true;
result &= (a() & b());
// a() and b() both will be called, but not necessarily in that order in an
// optimizing compiler

这一点尤为重要,因为您可能无法控制方法a()b() ,或者其他人可能会出现并在以后更改它们而不理解依赖项,并导致令人讨厌的(通常仅发布 - 构建)错误。

===============>>#3 票数:11

我认为

a != b

是你想要的

===============>>#4 票数:10

凸起的眉毛应该足以让你停止这样做。 您不编写编译器的代码,首先为其他程序员编写代码,然后编写代码。 即使编译器工作,令人惊讶的是其他人并不是你想要的 - 按位操作符不是用于bool操作。
我想你也用叉子吃苹果? 它有效,但它给人们带来惊喜,所以最好不要这样做。

===============>>#5 票数:7

bitlevel运算符的缺点。

你问:

“有没有理由不使用按位运算符&| ,和^用于C ++中的“bool”值?

是的, 逻辑运算符 ,即内置的高级布尔运算符! &&|| ,具有以下优点:

  • 保证将参数转换bool ,即01序数值。

  • 保证短路评估 ,一旦最终结果已知,表达式评估就会停止。
    这可以解释为树值逻辑,具有TrueFalseIndeterminate

  • 可读的文本等价物notandor ,即使我自己不使用它们。
    正如读者锑在评论中指出的那样,bitlevel运算符也有替代令牌,即bitandbitorxorcompl ,但在我看来,它们的可读性低于andor not

简而言之,高级运算符的每个这样的优点都是位级运算符的缺点。

特别是,由于按位运算符缺少参数转换为0/1,因此得到例如1 & 20 ,而1 && 2true 也是^ ,按位排他或者,可能以这种方式行为不端。 被视为布尔值1和2是相同的,即为true ,但被视为位图,它们是不同的。


如何表达逻辑要么/或 C ++。

然后,您提供一些问题的背景,

“我有时遇到两种情况中只有一种情况要求为真(XOR)的情况,所以我只是将^运算符抛出一个条件表达式。”

嗯,按位运算符的优先级高于逻辑运算符。 这尤其意味着在诸如的混合表达中

a && b ^ c

你得到了意想不到的结果a && (b ^ c)

而只是写

(a && b) != c

更简明扼要地表达你的意思。

对于多个参数要么/或没有C ++运算符来完成这项工作。 例如,如果你写a ^ b ^ c而不是一个表达“ abc为真”的表达式。 相反它说,“ abc的奇数是真的”,可能是其中1个或全部3个......

要表达一般/或者abcbool类型,只需写

(a + b + c) == 1

或者,使用非bool参数,将它们转换为bool

(!!a + !!b + !!c) == 1


使用&=累积布尔结果。

你进一步阐述,

“我有时也需要积累布尔值,而且&=|=? 可能非常有用。“

嗯,这相当于检查是否满足所有任何条件, de Morgan定律告诉你如何从一个到另一个。 即你只需要其中一个。 原则上你可以使用*=作为&&=符(对于旧的George Boole发现,逻辑AND可以非常容易地表示为乘法),但我认为这会困扰并可能误导代码的维护者。

还要考虑:

struct Bool
{
    bool    value;

    void operator&=( bool const v ) { value = value && v; }
    operator bool() const { return value; }
};

#include <iostream>

int main()
{
    using namespace std;

    Bool a  = {true};
    a &= true || false;
    a &= 1234;
    cout << boolalpha << a << endl;

    bool b = {true};
    b &= true || false;
    b &= 1234;
    cout << boolalpha << b << endl;
}

使用Visual C ++ 11.0和g ++ 4.7.1输出:

true
false

结果不同的原因是bitlevel &=不提供对其右侧参数的bool的转换。

那么,您希望使用哪些结果&=

如果前者为true ,则更好地定义运算符(例如,如上所述)或命名函数,或者使用右侧表达式的显式转换,或者完整地写入更新。

===============>>#6 票数:3

与Patrick的回答相反,C ++没有^^运算符来执行短路异或。 如果你考虑它一秒钟,拥有一个^^运算符无论如何都没有意义:使用exclusive或,结果总是取决于两个操作数。 然而,当比较1 & 21 && 2时,帕特里克关于非bool “布尔”类型的警告同样适用。 一个典型的例子是Windows GetMessage()函数,它返回一个三态BOOL :非零, 0-1

使用&而不是&&| 而不是|| 这不是一个罕见的拼写错误,所以如果你故意这样做,它应该得到一个评论说明为什么。

===============>>#7 票数:2

帕特里克提出了很好的观点,我不打算再重复一遍。 但是我可以建议尽可能通过使用名称很好的布尔变量将'if'语句减少到可读的英语。例如,这是使用布尔运算符,但你可以同样使用按位并适当地命名bool:

bool onlyAIsTrue = (a && !b); // you could use bitwise XOR here
bool onlyBIsTrue = (b && !a); // and not need this second line
if (onlyAIsTrue || onlyBIsTrue)
{
 .. stuff ..
}

您可能认为使用布尔值似乎是不必要的,但它有两个主要方面:

  • 您的代码更容易理解,因为'if'条件的中间布尔值使条件的意图更明确。
  • 如果您使用非标准或意外的代码,例如布尔值上的按位运算符,人们可以更容易地了解您为什么这样做。

编辑:你没有明确表示你想要'if'语句的条件(虽然这似乎很可能),这是我的假设。 但我对中间布尔值的建议仍然存在。

===============>>#8 票数:0

IIRC,许多C ++编译器在尝试将按位操作的结果转换为bool时会发出警告。 您必须使用类型转换才能使编译器满意。

在if表达式中使用按位运算会产生相同的批评,尽管可能不是由编译器引起的。 任何非零值都被认为是真的,所以“if(7&3)”之类的东西都是真的。 在Perl中这种行为是可以接受的,但C / C ++是非常明确的语言。 我认为Spock的眉毛是尽职尽责的。 :)我会追加“== 0”或“!= 0”,以明确你的目标是什么。

但无论如何,这听起来像是个人偏好。 我会通过lint或类似的工具运行代码,看看它是否也认为这是一个不明智的策略。 就个人而言,它看起来像编码错误。

===============>>#9 票数:-1

对bool使用按位运算有助于节省处理器不必要的分支预测逻辑,这是由逻辑运算引入的“cmp”指令产生的。

用位操作替换逻辑(其中所有操作数都是bool)生成更高效的代码,提供相同的结果。 理想情况下,效率应该超过使用逻辑运算在订购中可以利用的所有短路优势。

这可能会使代码有点不可读,尽管程序员应该对其进行评论,理由是为什么这样做。

  ask by Jay Conrod translate from so

未解决问题?本站智能推荐: