为什么'&&'而不是'&'?
为什么 &&
优于 &
且 ||
优于 |
?
我问了一个多年来一直在编程的人,他的解释是:
例如,在 if (bool1 && bool2 && bool3) { /*DoSomething*/ }
中,bool1
必须为 true 才能测试 bool2
,在转向 bool3
之前必须为 true。如果我使用了单个&
相反,即使所有测试都必须正确才能进入下一行,但测试没有顺序,那么为什么它很重要呢?
注意:我想指出的是,我的编程能力相当于一个幼儿,这不是一个严肃或紧急的问题。更重要的是理解为什么事情应该以某种方式而不是另一种方式完成。
Why is &&
preferable to &
and ||
preferable to |
?
I asked someone who's been programming for years and his explanation was:
For example, in if (bool1 && bool2 && bool3) { /*DoSomething*/ }
, bool1
has to be true for it to test bool2
which has to be true before moving on to bool3
, etc. If I'd used a single &
instead there is no order to the test even if all of them have to be true to progress to the next line, so why does it matter anyway?
Note: I'd like to point out that I'm the programming equivalent of a toddler and this is not a serious or urgent question. It's more a matter of understanding why things should be done a certain way as opposed to another.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
在大多数情况下,
&&
和||
优于&
和|
,因为前者短路,即结果明确后立即取消评估。示例:
如果
CanExecute
返回false
,则完整表达式将为false
,无论CanSave
的返回值如何。因此,CanSave
不会被执行。这在以下情况下非常方便:
如果在字典中找不到提供的键,则
TryGetValue
返回false
。由于&&
的短路性质,value.Contains("test")
仅在TryGetValue
返回 < code>true 因此value
不是null
。如果您使用按位与运算符&
,如果在字典中找不到该键,您将得到一个NullReferenceException
,因为在任何情况下都会执行表达式的第二部分。一个类似但更简单的示例是以下代码(如 TJHeuvel 提到的):
仅当
op
不为null
时才执行CanExecute
。如果op
为null
,则表达式的第一部分 (op != null
) 计算结果为false
,并且其余部分的评估 (op.CanExecute()
) 将被跳过。除此之外,从技术上来说,它们也不同:
&&
和||
只能用于bool
,而&
和|< /code> 可用于任何整数类型(
bool
、int
、long
、sbyte
、... ),因为它们是按位运算符。&
是按位 AND 运算符,|
是按位 OR 运算符。更准确地说,在 C# 中,这些运算符(
&
、|
[和^
])称为“逻辑运算符”(请参阅C# 规范,第 7.11 章)。这些运算符有多种实现:int
、uint
、long
和ulong
,第 7.11 章。 1):它们被实现来计算操作数和运算符的按位结果,即
&
被实现来计算按位逻辑AND
等。它们被实现来执行枚举的基础类型的逻辑操作。
结果不是使用按位计算来计算的。结果基本上是根据两个操作数的值来查找的,因为可能性的数量太少了。
由于两个值都用于查找,因此此实现不会短路。
In most cases,
&&
and||
are preferred over&
and|
because the former are short-circuited, meaning that the evaluation is canceled as soon as the result is clear.Example:
If
CanExecute
returnsfalse
, the complete expression will befalse
, regardless of the return value ofCanSave
. Because of this,CanSave
is not executed.This is very handy in the following circumstance:
TryGetValue
returnsfalse
if the supplied key is not found in the dictionary. Because of the short-circuiting nature of&&
,value.Contains("test")
is only executed, whenTryGetValue
returnstrue
and thusvalue
is notnull
. If you would use the bitwise AND operator&
instead, you would get aNullReferenceException
if the key is not found in the dictionary, because the second part of the expression is executed in any case.A similar but simpler example of this is the following code (as mentioned by TJHeuvel):
CanExecute
is only executed ifop
is notnull
. Ifop
isnull
, the first part of the expression (op != null
) evaluates tofalse
and the evaluation of the rest (op.CanExecute()
) is skipped.Apart from this, technically, they are different, too:
&&
and||
can only be used onbool
whereas&
and|
can be used on any integral type (bool
,int
,long
,sbyte
, ...), because they are bitwise operators.&
is the bitwise AND operator and|
is the bitwise OR operator.To be very exact, in C#, those operators (
&
,|
[and^
]) are called "Logical operators" (see the C# spec, chapter 7.11). There are several implementations of these operators:int
,uint
,long
andulong
, chapter 7.11.1):They are implemented to compute the bitwise result of the operands and the operator, i.e.
&
is implement to compute the bitwise logicalAND
etc.They are implemented to perform the logical operation of the underlying type of the enumeration.
The result is not computed using bitwise calculations. The result is basically looked up based on the values of the two operands, because the number of possibilities is so small.
Because both values are used for the lookup, this implementation isn't short-circuiting.
非常清楚地解释这意味着什么(即使其他答案暗示它 - 但可能使用您不理解的术语)。
以下代码:
真正编译为:
其中以下代码完全按照其表示的方式编译:
这称为短路。一般来说,您应该始终在您的条件中使用
&&
和||
。奖励分数:有一种情况是您不应该这样做的。如果您处于性能至关重要的情况(这是纳秒至关重要),则仅在必须时才使用短路(例如
null
检查) - 作为短路-电路是分支/跳转;这可能会导致 CPU 上的分支预测错误;&
比&&
便宜得多。还有一种情况,短路实际上会破坏逻辑 - 看看 我的这个答案。谩骂/独白:关于最幸福地忽略的分支错误预测。引用 Andy Firth(一直致力于游戏开发) 13 年):“这可能是人们认为他们需要达到的较低水平......但他们错了。了解您正在编程的硬件如何处理分支可以极大地影响性能程度……远远超过大多数程序员可能欣赏的《re:千刀万剐》。”
这是非信徒的基准。最好以 RealTime/High 运行该进程,以减轻调度程序的影响:https://gist.github。 com/1200737
To explain very clearly what this means (even though the other answers hint at it - but probably use terminology you don't understand).
The following code:
Is really compiled to this:
Where the following code is compiled exactly as it is represented:
This is called short-circuiting. In general you should always use
&&
and||
in your conditions.Bonus Marks: There is one scenario when you shouldn't. If you are in a situation where performance is crucial (and this is nano-seconds crucial) only use short-circuiting when you must (e.g.
null
checking) - as a short-circuit is a branch/jump; which could result in a branch-misprediction on your CPU; an&
is much cheaper than&&
. There is also a scenario where short-circuiting can actually break logic - have a look at this answer of mine.Diatribe/Monologue: Regarding the branch mis-prediction that most blissfully ignore. Quoting Andy Firth (who has been working on games for 13 years): "This may be lower level that people think they need to go... but they'd be wrong. Understanding how the hardware you're programming for treats branches can affect performance to a HUGE degree... far more than most programmers may appreciate re: death by a thousand cuts."
Here is a benchmark for the non-believers. It's best to run the process in RealTime/High to mitigate the scheduler having an effect: https://gist.github.com/1200737
逻辑运算符(
||
和&&
)与按位运算符(|
和&
)。逻辑运算符和按位运算符之间最重要的区别在于,逻辑运算符采用两个布尔值并生成一个布尔值,而按位运算符采用两个整数并生成一个整数(注意:整数表示任何整数数据类型,而不仅仅是 int)。
迂腐地说,按位运算符采用位模式(例如 01101011)并对每个位执行按位 AND/OR 操作。因此,例如,如果您有两个 8 位整数:
而逻辑运算符仅适用于
bool
:其次,通常可以在 bool 上使用按位运算符,因为 true 和 false 相当于 1和 0 分别,并且恰好将 true 翻译为 1,将 false 翻译为 0,然后进行按位运算,然后将非零转换为 true,将 0 转换为 false;如果您刚刚使用逻辑运算符,结果会是相同的(检查此练习)。
另一个重要的区别是逻辑运算符是短路的。因此,在某些圈子[1]中,你经常会看到人们做这样的事情:
“如果人存在(即不为空),则尝试打他/她,如果打成功(即返回 true),然后跳一支胜利之舞”。
如果您使用按位运算符,则:
将转换为:“如果人存在(即不为空)并且出拳成功(即返回 true),则跳胜利之舞”。
请注意,在短路逻辑运算符中,如果
person
为 null,则person.punch()
代码可能根本不会运行。事实上,在这种特殊情况下,如果person
为 null,第二个代码将产生空引用错误,因为无论 person 是否为空,它都会尝试调用person.punch()
是否为空。这种不评估正确操作数的行为称为短路。[1] 一些程序员会反对将具有副作用的函数调用放入
if
表达式中,而对于其他程序员来说,这是一种常见且非常有用的习惯用法。由于按位运算符一次在 32 位上运行(如果您使用的是 32 位机器),因此如果您需要比较大量条件(例如,
执行相同操作 ),它可以生成更优雅、更快的代码使用逻辑运算符将需要大量的比较:
使用位模式和按位运算符的典型示例是在 Unix/Linux 文件系统权限中。
Logical operator (
||
and&&
) vs. bitwise operator (|
and&
).The most crucial difference between a logical operator and bitwise operator is that a logical operator takes two booleans and produces a boolean while a bitwise operator takes two integers and produces an integer (note: integers means any integral data type, not just int).
To be pedantic, a bitwise operator takes a bit-pattern (e.g. 01101011) and does a bit-wise AND/OR on each bits. So, for example if you have two 8-bit integers:
while a logical operator only works in
bool
:Second, it is often possible to use a bitwise operator on bool since true and false is equivalent to 1 and 0 respectively, and it happens that if you translate true to 1 and false to 0, then do bitwise operation, then convert non-zero to true and zero to false; it happens that the result will be the same had you just used logical operator (check this for exercise).
Another important distinction is also that a logical operator is short-circuited. Thus, in some circles[1], you often see people doing something like this:
which translates to: "if person exists (i.e. is not null), try to punch him/her, and if the punch succeeds (i.e. returns true), then do a victory dance".
Had you used a bitwise operator instead, this:
will translate to: "if person exists (i.e. is not null) and the punch succeeds (i.e. returns true), then do a victory dance".
Note that in the short-circuited logical operator, the
person.punch()
code may not be run at all ifperson
is null. In fact, in this particular case, the second code would produce a null reference error ifperson
is null, since it tries to callperson.punch()
no matter whether person is null or not. This behavior of not evaluating the right operand is called short-circuiting.[1] Some programmers will baulk for putting a function call that have a side effect inside an
if
expression, while for others it's a common and very useful idiom.Since a bitwise operator works on 32-bits at a time (if you're on a 32-bit machine), it can lead to a more elegant and faster code if you need to compare a huge number of conditions, e.g.
Doing the same with logical operators would require an awkward amount of comparisons:
A classical example where bit-patterns and bitwise operator are used is in Unix/Linux file system permissions.
在以下情况下:
将按预期工作。
但是:
可能会引发空引用异常。
In the case of:
would work as expected.
But:
could potentially throw a null reference exception.
简短而简单:
1 && 2
= true因为
1 = C 中的 true(非零)
C 中的 2 = true(非零)
true
与true
进行逻辑与得到true
。但是
1 & 2
= 0 = 假因为
1 = 二进制 0001
2 = 二进制 0010
0001 与 0010 按位与,得到十进制 0000 = 0。
对于 || 同样如此和 |运营商也...!
Short and simple:
1 && 2
= truebecause
1 = true (non-zero) in C
2 = true (non-zero) in C
true
ANDS logically withtrue
to givetrue
.But
1 & 2
= 0 = falsebecause
1 = 0001 in binary
2 = 0010 in binary
0001 ANDs bitwise with 0010 to give 0000 = 0 in decimal.
Likewise for || and | operators too...!
&&
是&
的短路版本。如果我们正在评估 false & true,从第一个参数我们已经知道结果将为 false。
&&
版本的运算符将尽快返回结果,而不是计算整个表达式。还有一个类似版本的|
运算符||
。&&
is the short circuit version of&
.If we are evaluating
false & true
, we already know from looking at the first argument that the result will be false. The&&
version of the operator will return a result as soon as it can, rather than evaluate the whole expression. There is also a similar verion of the|
operator,||
.安全会崩溃。
如果列表的大小不正确,则
is safe
would crash if the list doesn't have the right size.
C# 运算符 应该解释原因:
本质上有两个
&
或|
意味着它是条件而不是逻辑,因此您可以区分 二。& Operator 有一个使用
&
的示例。C# Operators should explain why:
Essentially having two
&
's or|
's means that it is a conditional rather than a logical, so you can tell the difference between the two.& Operator has an example of using one
&
.好的,从表面上看,
会产生相同的答案。但是,正如您所展示的,如果您有一个更复杂的问题,那么:
如果
a
不正确,并且可能b
是一个必须关闭的函数,请连接到某个东西,得到这个,做那个,做出决定..何苦呢?浪费时间,你知道它已经失败了。为什么要让机器停机并做额外的无意义的工作?我一直使用
&&
因为我把最有可能失败的放在第一位,因此,在没有意义的情况下,在继续之前进行更少的计算。如果无法预测不太可能的选择,例如您有一个布尔值来限制数据输出,例如:如果不是
limit
,则不必费心检查密钥,这可能需要更长..OK, on face value
produce the same answer. However, as you showed, if you have a more complex question so:
If
a
is not true and maybeb
is a function where it has to go off, connect to something, get this, do that, make a decision.. why bother? Waste of time, you know it's already failed. Why make the machine go off and do extra pointless work?I've always used
&&
because I put the most likely to fail first, ergo, less calculations before moving on when there is no point. If there is no way to predict less likely choices, such as you have a boolean to limit output of data, something like:If it's not
limit
, don't bother checking for the key, which could take longer..当在逻辑表达式(例如 if 语句)中使用时,
&&
更好,因为一旦遇到第一个错误结果,它就会停止计算表达式。这是可能的,因为假值将导致整个表达式为假。类似地(同样在逻辑表达式中)||
更可取,因为一旦遇到 true 表达式,它就会停止计算表达式,因为任何 true 值都会导致整个表达式为 true。但是,如果 or 或 and 一起的表达式有副作用,并且您希望所有这些都作为表达式的结果发生(无论逻辑表达式的结果如何),则
&和
|
。相反,&&
和||
运算符可用于防止不必要的副作用(例如导致引发异常的空指针)。&
和|
运算符也可以与整数一起使用,在这种情况下,它们生成一个整数结果,该结果是两个操作数在位级别。当整数值的二进制位用作真值和假值的数组时,这非常有用。为了测试某个位是打开还是关闭,位掩码与该值进行按位与运算。要打开某个位,可以将同一掩码与该值进行按位或运算。最后要关闭一点,掩码的按位补码(使用~
)与值进行按位与运算。在 C# 以外的语言中,必须注意 & 的逻辑模式与按位模式。和|。在上面的代码中,
if
语句的条件表达式(a & 4) != 0
是表达此条件的安全方式,但在许多类似 C 的语言中,条件表达式语句可以简单地将零整数值视为 false,将非零整数值视为 true。 (其原因与可用的条件分支处理器指令以及它们与每次整数运算后更新的零标志的关系有关。)因此可以删除ìf
语句对零的测试,并且条件可以缩短为(a & 4)
。当使用按位和运算符组合表达式返回没有位对齐的值时,这可能会导致混乱,甚至可能出现问题。考虑以下示例,其中需要两个函数的副作用,然后再检查它们是否都成功(按照它们返回非零值的定义):
在 C 中,如果
foo()
返回1 且bar()
返回 2,“某事”不会完成,因为1 & 2
为零。C# 要求像
if
这样的条件语句具有布尔值,并且该语言不允许将整数值转换为布尔值。所以上面的代码会产生编译器错误。更正确的表达方式如下:When used in a logical expression such as an if statement
&&
preferable because it will stop evaluating expressions as soon as the first false result is encountered. This is possible because a false value will cause the entire expression to be false. Similarly (and again in logical expressions)||
is preferable because it will stop evaluating expressions as soon as it encounters a true expression because any true value will cause the entire expression to be true.If however the expressions being or-ed or and-ed together have side effects, and you want all of these to happen as a result of your expression (regardless of the outcome of the logical expression), then
&
and|
could be used. Conversely, the&&
and||
operators can be useful as guards against unwanted side-effects (such as a null pointer causing an exception to be thrown).The
&
and|
operators can also be used with integers and in this case they produce an integer result which is the two operands and-ed or or-ed together at the bit level. This can be useful when an integer value's binary bits are used as an array of true and false values. To test whether a certain bit is on or off, a bit-mask is bitwise and-ed with the value. To turn a bit on, the same mask can be bitwise or-ed with the value. Finally to turn a bit off, the bitwise complement (using~
) of a mask is bitwise and-ed with the value.In languages other than C#, care must be taken with the logical versus bitwise modes of & and |. In the code above, the
if
statement's conditional expression(a & 4) != 0
is a safe way to express this condition, but in many C like languages, conditional statements can simply treat zero integer values as false and non-zero integer values as true. (The reason for this relates to the conditional branch processor instructions available, and their relationship to the zero flag that is updated after every integer operation.) So theìf
statement's test for zero can be removed and the condition could be shortened to(a & 4)
.This could cause confusion and maybe even problems when expressions combined using the bitwise and operator return values that don't have bits that line up. Consider the following example where the side-effects of two functions are desired, before checking that they were both successful (as defined by them returning a non-zero value):
In C, if
foo()
returns 1 andbar()
returns 2, the "something" won't be done because1 & 2
is zero.C# requires conditional statements like
if
to have a boolean oeprand, and the language doesn't allow an integer value to be cast to a boolean value. So the code above would generate compiler errors. It would more correctly be expressed as follows:如果您是一位老 C 程序员,请小心。 C# 真的让我很惊讶。
MSDN 表示
|
运算符:(强调是我的。)布尔类型是经过特殊处理的,在这种情况下,问题才开始有意义,区别在于,正如其他人在其答案中已经解释的那样:
更可取的取决于许多因素,例如副作用、性能和代码可读性,但通常短路运算符更可取,因为像我这样具有相似背景的人可以更好地理解它们。
原因是:我会这样论证:由于 C 中没有真正的布尔类型,因此您可以使用按位运算符
|
并在 if 条件下将其结果评估为 true 或 false。但这对于 C# 来说是错误的态度,因为布尔类型已经有了特殊情况。If you are an old-timer C programmer, be careful. C# has really surprised me.
MSDN says for the
|
operator:(Emphasis is mine.) Boolean types are handled specially, and in this context the question only starts to make sense, and the difference is, as other already expained in their answers:
and what's preferable depends on many things like side-effects, performance and code readability, but generally the short-circuiting operators are preferable also because they are better understood by people with a similar background like me.
The reason is: I would argument like this: Since there is no real boolean type in C, you could use the bitwise operator
|
and have its result evaluated as truthy or falsy in an if condition. But this is the wrong attitude for C#, because there is already a special case for boolean types.这很重要,因为如果 bool2(例如)的评估成本很高,但 bool1 为假,那么您可以通过使用 && 节省大量计算量。超过&
It's important, because if the cost of evaluation of bool2 (for instance) is high but bool1 is false, then you've saved yourself a fair bit of computation by using && over &
因为
&&
和||
就像if/else
一样用于流控制。它并不总是与条件有关。写成语句是完全合理的,而不是写成if
或while
条件,如下:或者甚至
不仅仅是它这些比等效的
if/else
版本更容易输入;它们也更容易阅读和理解。Because
&&
and||
are used for flow control just likeif/else
are. It isn’t always about conditionals. It is perfectly reasonable to write as a statement, not as anif
or awhile
conditional, the following:or even
It’s not just that it those are easier to type than the equivalent
if/else
versions; they are also much easier to read and understand.&&和&意味着两个截然不同的事情并给你两个不同的答案。
<代码>1 && 2 产生 1(“true”)
<代码>1 & 2 产生 0(“假”)
&&
是一个逻辑运算符 - 它的意思是“如果两个操作数都为 true,则为 true”&
是按位比较。它的意思是“告诉我两个操作数中设置了哪些位”&& and & mean two very different things and give you two different answers.
1 && 2
yields 1 ("true")1 & 2
yields 0 ("false")&&
is a logic operator -- it means "true if both of the operands are true"&
is a bitwise comparison. It means "tell me which of the bits are set in both of the operands"向不需要知道代码的确切操作的人解释这一点的最快(并且稍微简单)的方法是
&& 是对每个条件进行检查< strong>Until 它找到一个 false 并将整个结果返回为 false
|| 正在对每个条件进行检查 Until 它找到一个 true 并返回整个结果都是真实的。
& 正在根据两个/所有条件进行数学计算并处理结果。
| 正在根据两个/所有条件进行数学计算并处理结果。
我从未遇到过需要在 if 语句中使用 & 或 | 的情况。我主要使用它通过按位移位将十六进制值分割为其分量颜色。
EG:
在此操作中“& 0xFF”强制仅查看二进制值。
不过,我个人还没有发现 | 的用途。
Quickest (and slightly dumbed down) way to explain this to people who do not NEED to know the exact operations of the code when doing this is
&& is doing a check on each of those conditions Until it finds a false and returns the entire outcome as false
|| is doing a check on each of those conditions Until it finds a true and returns the entire outcome as true.
& is doing MATHS based apon BOTH/ALL the conditions and dealing with the outcome.
| is doing MATHS based apon BOTH/ALL the conditions and dealing with the outcome.
I've never come across a point where I have needed to use & or | within an if statement. I mostly use it for cutting up Hexadecimal values into its component colours using bitwise shift.
EG:
Within this operation "& 0xFF" is forcing to only look at of the binary value.
I have not personally found a use for | yet though.
简单来说,
if exp1 && exp2
如果 exp1 是
flase
不检查 exp2,
而是检查
if exp1 & exp2
如果 exp1 为
false
或true
检查 exp2
并且很少有人使用
&
因为他们很少想在 exp1 为false
时检查 exp2Simply,
if exp1 && exp2
if exp1 is
flase
don't check exp2
but
if exp1 & exp2
if exp1 is
false
Ortrue
check exp2
and rarely people use
&
because they rarely want to check exp2 if exp1 isfalse