有没有理由不在C ++中使用按位运算符&,|和^作为“bool”值?
我有时遇到两种情况中只有一种是真的(XOR)的情况,所以我只是将^运算符抛出到条件表达式中。我有时也希望评估条件的所有部分是否真实(而不是短路),所以我使用&和|。我有时也需要积累布尔值,而且& =和| =非常有用。
这样做时我已经有了一些眉毛,但代码仍然有意义且比其他方式更清晰。是否有任何理由不将这些用于布尔?是否有任何现代编译器可以为此提供不良结果?
答案 0 :(得分:48)
||
和&&
是布尔运算符,内置函数保证返回true
或false
。没别了。
|
,&
和^
是按位运算符。当你操作的数字域只有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
类型只能保证true
或false
(隐式转换为1
和0
因此,这种立场并不是一种担心,但是人们不习惯在代码中看到这样的事情这一事实对于不这样做是一个很好的理由。只需说出b = b && x
并完成它。
答案 1 :(得分:25)
两个主要原因。总之,要仔细考虑;这可能是一个很好的理由,但如果你的评论中有非常明确的原因,因为它可能很脆弱,正如你自己所说,人们通常不习惯看到这样的代码。
首先,如果您使用false
和true
(或0
和1
以外的值作为整数运算,^
运算符可以引入的行为不等同于逻辑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()
,或者其他人可能会出现并在以后更改它们而不理解依赖关系,并导致讨厌(并且经常发布 - 构建只有)bug。
答案 2 :(得分:11)
我认为
a != b
是你想要的
答案 3 :(得分:9)
凸起的眉毛应该足以让你停止这样做。您不编写编译器的代码,首先为其他程序员编写代码,然后编写代码。即使编译器工作,令人惊讶的是其他人不是你想要的 - 按位运算符不是用于bool的位操作。
我想你也用叉子吃苹果?它有效,但它给人们带来惊喜,所以最好不要这样做。
答案 4 :(得分:6)
你问:
“有没有理由不在C ++中使用按位运算符
&
,|
和^
作为”bool“值? “
是的,逻辑运算符,即内置的高级布尔运算符!
,&&
和||
,具有以下优势: / p>
保证将参数转换为bool
,即0
和1
序数值。
保证短路评估,一旦知道最终结果,表达式评估就会停止。
这可以解释为树值逻辑, True , False 和 Indeterminate 。
可读的文字对等not
,and
和or
,即使我自己也不使用它们。
正如读者锑在评论中指出的那样,位级运算符也有替代标记,即bitand
,bitor
,xor
和compl
,但在我看来,它们的可读性低于and
。 {1}},or
和not
。
简单地说,高级运算符的每个优点都是位级运算符的缺点。
特别是,由于按位运算符缺少参数转换为0/1,因此1 & 2
→0
,而1 && 2
→true
。同样^
,按位排他,或者可能以这种方式行为不端。被视为布尔值1和2是相同的,即true
,但被视为位图,它们是不同的。
<小时/>
然后,您提供了一些问题的背景知识,
“我有时遇到两种情况中只有一种是真实的情况(XOR),所以我只是将^运算符抛出一个条件表达式。”
嗯,按位运算符的优先级高于逻辑运算符。这尤其意味着在混合表达中,例如
a && b ^ c
你得到了意想不到的结果a && (b ^ c)
。
而只是写
(a && b) != c
更简明扼要地表达你的意思。
对于多个参数或/或,没有C ++运算符可以完成这项工作。例如,如果您编写a ^ b ^ c
而不是表达“a
,b
或c
为真”的表达式。相反,它说,“奇数a
,b
和c
都是真的”,可能是其中一个或全部3个......
要表达一般性/或a
,b
和c
属于bool
,只需写一下
(a + b + c) == 1
或使用非bool
参数,将它们转换为bool
:
(!!a + !!b + !!c) == 1
<小时/>
&=
累积布尔结果。你进一步详细说明,
“我有时也需要积累布尔值,
&=
和|=?
非常有用。”
嗯,这对应于检查是否满足所有或任何条件, de Morgan定律告诉您如何从一个到另一个。即你只需要其中一个。你原则上可以使用*=
作为&&=
- 运算符(对于旧的George Boole发现,逻辑且可以很容易地表示为乘法),但我认为那会困扰并可能误导维护者代码。
还要考虑:
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
结果不同的原因是位等级&=
未向其右侧参数bool
提供转换。
那么,您希望使用&=
?
如果前者true
,则更好地定义运算符(例如,如上所述)或命名函数,或使用右侧表达式的显式转换,或者完整地写入更新。
答案 5 :(得分:3)
与Patrick的回答相反,C ++没有^^
运算符用于执行短路异或。如果你考虑它一秒钟,拥有^^
运算符无论如何都没有意义:使用exclusive或者,结果总是取决于两个操作数。但是,在将bool
与1 & 2
进行比较时,Patrick对非1 && 2
“布尔”类型的警告同样适用。一个典型的例子是Windows GetMessage()
函数,它返回一个三态BOOL
:非零,0
或-1
。
使用&
代替&&
和|
代替||
并不是一个罕见的拼写错误,所以如果您故意这样做,那么值得发表评论说明原因。
答案 6 :(得分:2)
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'语句的条件(虽然这似乎很可能),这是我的假设。但我对中间布尔值的建议仍然存在。
答案 7 :(得分:0)
在if表达式中使用按位运算会产生同样的批评,尽管可能不是编译器。任何非零值都被认为是真的,所以像“if(7&amp; 3)”这样的东西都是真的。在Perl中这种行为是可以接受的,但C / C ++是非常明确的语言。我认为Spock的眉毛是尽职尽责的。 :)我会追加“== 0”或“!= 0”来清楚地说明你的目标是什么。
但无论如何,这听起来像是个人偏好。我会通过lint或类似的工具运行代码,看看它是否也认为这是一个不明智的策略。就个人而言,它看起来像编码错误。
答案 8 :(得分:0)
对bool使用按位运算有助于节省处理器不必要的分支预测逻辑,这是由于cmp&#39;逻辑运算引入的指令。
用位操作替换逻辑(其中所有操作数都是bool)生成更高效的代码,提供相同的结果。理想情况下,效率应该超过使用逻辑运算在订购中可以利用的所有短路优势。
这可能会使代码有点不可读,尽管程序员应该对其进行评论,理由是为什么这样做。