A clear, layman's explanation of the difference between | and || in c#?
好吧,我已经读过很多次了,但是我还没有听到一种清晰、易懂(和令人难忘)的方法来学习以下两者之间的区别:
1 | if (x | y) |
和
1 | if (x || y) |
..在C的上下文中。有人能帮我了解这个基本事实吗,以及C具体地说,如何区别对待他们(因为他们似乎做了同样的事情)。如果一段给定的代码之间的差异是无关的,那么作为最佳实践,我应该默认哪个?
1 2 3 | // Example var one = true || bar(); // result is true; bar() is never called var two = true | bar(); // result is true; bar() is always called |
1 2 3 4 5 6 | // Example var a = 0x10; var b = 0x01; var c = a | b; // 0x11 == 17 var d = a || b; // Compile error; can't apply || to integers var e = 0x11 == c; // True |
对于布尔操作数,
If the difference a given piece of code has between them is irrelevant, which should I default to as a best-practise?
如前所述,两者之间的差异并不无关紧要,因此这个问题在一定程度上是没有意义的。至于"最佳实践",没有一个:您只需使用正确的运算符。一般来说,人们喜欢
与布尔操作数一起使用时,
这意味着第二个操作数总是使用
两个运算符的表达式结果总是相同的,但如果第二个操作数的计算导致其他内容发生更改,则只有使用
例子:
1 2 3 4 5 6 7 8 9 10 | int a = 0; int b = 0; bool x = (a == 0 || ++b != 0); // here b is still 0, as the"++b != 0" operand was not evaluated bool y = (a == 0 | ++b != 0); // here b is 1, as the"++b != 0" operand was evaluated. |
1 2 3 4 5 6 7 8 9 | if (str == null) { Console.WriteLine("String has to be at least three characters."); } else { if (str.Length < 3) { Console.WriteLine("String has to be at least three characters."); } else{ Console.WriteLine(str); } } |
你可以这样写:
1 2 3 4 5 | if (str == null || str.Length < 3) { Console.WriteLine("String has to be at least three characters."); } else{ Console.WriteLine(str); } |
第二个操作数只有在第一个操作数为false时才进行计算,因此您知道可以安全地在第二个操作数中使用字符串引用,因为如果计算第二个操作数,则它不能为空。
在大多数情况下,您希望使用
它们不一样。一个是位"或",一个是逻辑"或"。
x y是逻辑或,表示与"x或y"相同,适用于bool值。它用于条件或测试中。在这种情况下,x和y可以替换为任何计算为bool的表达式。例子:
1 | if (File.Exists("List.txt") || x > y ) { ..} |
如果这两个条件之一为真,则子句的计算结果为真。如果第一个条件为真(如果文件存在),则第二个条件不需要也不会被计算。
单管()是按位或。要知道这意味着什么,你必须了解数字是如何存储在计算机中的。假设您有一个16位的数量(int16),它保存值15。它实际存储为0x000F(十六进制),与0000 0000 0000 1111(二进制)相同。按位"或"将两个量和"或"的每对对应的位放在一起,这样,如果两个量中的一个位为1,则结果为1。因此,如果a=0101 0101 0101(十六进制为0x5555),b=1010 1010 1010(十六进制为0xAAAA),则a b=1111 1111 1111 1111=0xffff。
您可以使用C中的位或(单管)来测试是否打开了一组特定的位中的一个或多个。如果要测试12个布尔值或二进制值,并且它们都是独立的,那么可以这样做。假设您有一个学生数据库。一组独立的布尔值可能是这样的:男性/女性、家庭/校园内、当前/非当前、已注册/未注册等。如果不为这些值中的每一个存储布尔字段,则可以为每个值存储一个位。男性/女性可能是1号钻头。已注册/未注册可能是位2。
然后你可以用
1 | if ((bitfield | 0x0001) == 0x0001) { ... } |
作为测试,看是否没有位被打开,除了"学生是男性"位,这是被忽略的。呵呵?好吧,按位或返回一个1,表示在任何一个数中打开的每个位。如果位或以上的结果=0x001,这意味着位字段中没有打开的位,除了第一个位(0x001),但您不能确定第一个位是否打开,因为它被屏蔽了。
有一个对应的&;&;and&;,它是逻辑的和位的和。他们有类似的行为。
你可以使用
1 | if ((bitfield & 0x0001) == 0x0001) { ... } |
查看是否在位字段中打开了第一个位。
编辑:我真不敢相信我被投票否决了!
不像大多数答案,到目前为止,意思是不完全一样,在C++中。
对于计算布尔值的任何两个表达式a和b,a b和a b执行几乎相同的操作。
A B同时计算A和B,如果其中一个计算为真,则结果为真。
A B做了几乎相同的事情,只是它先计算A,然后在必要时才计算B。如果a或b为真,则整个表达式都为真,如果a为真,则根本不需要测试b。因此短路,并在可能的情况下跳过对第二个操作数的计算,其中运算符将始终对这两个操作数进行计算。
运算符不经常使用,而且通常不会产生影响。我能想到的唯一一个不同之处是:
1 2 3 | if ( foo != null || foo.DoStuff()){ // assuming DoStuff() returns a bool } |
这是因为如果左测试失败,则从不调用dostuff()成员函数。也就是说,如果foo为空,我们就不会在其上调用dostuff。(这将给我们一个nullreferenceexception)。
如果我们使用了运算符,那么无论foo是否为空,都将调用dostuf()。
在整数上,只有运算符被定义,并且是位"或",正如其他答案所描述的那样。但是运算符没有为整数类型定义,因此很难将它们混合到C中。
好的答案,但我要补充一点,如果左侧表达式是
|是按位或运算符(数字、整数)。它的工作原理是将数字转换成二进制,然后对每个对应的数字执行或。同样,数字在计算机中已经用二进制表示,因此在运行时不会真正发生这种转换;)
||是逻辑或运算符(布尔值)。它只适用于真值和假值。
下面将在C/C++中工作,因为它没有布尔类的第一类支持,它将每个表达式的"on"位视为真,否则为false。事实上,如果X和Y是数字类型,下面的代码将不能在C或Java中工作。
1 | if (x | y) |
所以上面代码的显式版本是:
1 | if ( (x | y) != 0) |
在C语言中,任何在其上有"on"位的表达式都会得到true。
int i=8;
如果(i)//在c中有效,则结果为真
IN-JOY=- 10;
如果(joy)//在c中无效,则结果为真
现在回到C
如果x和y是数字类型,则代码:if(x_y)将不起作用。你试过编译它吗?它不起作用
但是对于您的代码,我可以假定x和y是布尔类型,所以它会起作用,所以对于布尔类型,和之间的区别是,是短路的,而不是。以下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | static void Main() { if (x | y) Console.WriteLine("Get"); Console.WriteLine("Yes"); if (x || y) Console.WriteLine("Back"); Console.ReadLine(); } static bool x { get { Console.Write("Hey"); return true; } } static bool y { get { Console.Write("Jude"); return false; } } |
是:
1 2 3 | HeyJudeGet Yes HeyBack |
Jude不会被打印两次,其中是一个布尔运算符,许多C派生语言布尔运算符短路,如果布尔表达式短路,则布尔表达式的性能更高。
对于外行术语,当您说短路时,例如在(或运算符)中,如果第一个表达式已经为真,则不需要计算第二个表达式。示例:如果(answer='y'answer='y'),如果用户按small y,则程序不需要计算第二个表达式(answer='y')。那是短路。
在我上面的示例代码中,x是真的,因此y on运算符不会被进一步评估,因此没有第二个"jude"输出。
即使x和y是布尔类型,也不要在c中使用这种代码:if(x y)。不表演。
强烈建议从dotnet mob阅读本文
For OR logical operation if any of it's operand is evaluated to true then
whole expression is evaluated to true
这就是操作符所做的-当它找到一个真值时,它跳过剩余的评估。虽然运算符计算它的完整操作数以评估整个表达式的值。
1 2 3 4 5 6 7 8 | if(true||Condition1())//it skip Condition1()'s evaluation { //code inside will be executed } if(true|Condition1())//evaluates Condition1(), but actually no need for that { //code inside will be executed } |
无论是或()或和(&;&;)运算符,最好使用短路版本的逻辑运算符。
考虑以下代码段
1 2 3 4 5 6 7 | int i=0; if(false||(++i<10))//Now i=1 { //Some Operations } if(true||(++i<10))//i remains same, ie 1 {} |
这种效果称为副作用,实际上在表达式的右侧用短路逻辑运算符表示。
参考:C中的短路评估#
在不以任何方式、形状或形式钻研细节的情况下,这里有一个真正的外行版本。
把英语中的""想象成一个直线或",把英语中的""想象成"或"其他"。
同样,在英语中也可以将"&;as"和"视为";在英语中也可以将"&;&;as"和"视为"。
如果你用这些术语给自己读一个表达,它们通常会更有意义。
第一个位运算符处理两个数值,得到第三个数值。
如果你有二进制变量
1 2 | a = 0001001b; b = 1000010b; |
然后
1 | a | b == 1001011b; |
也就是说,如果结果中的某个位在任一操作数中也是1,则该位就是1。(为了清晰起见,我的示例使用8位数字)
"double pipe",是一个逻辑或运算符,它接受两个布尔值并产生第三个值。
虽然这句话已经被正确地说和回答了,我想我会添加一个真正的外行的答案,因为很多时候,这是我在这个网站上的感觉:)。另外,我将添加&vs.&;的示例,因为它是相同的概念
V.V.*
基本上,如果第一个部分是错误的,那么您倾向于使用来评估第二个部分。因此:
1 | if (func1() || func2()) {func3();} |
是一样的
1 2 3 4 5 6 7 8 | if (func1()) { func3(); } else { if (func2()) {func3();} } |
这可能是节省处理时间的一种方法。如果处理func2()花费了很长时间,那么如果func1()已经为真,则不希望执行此操作。
&与
在&vs.&;的情况下,类似的情况是,如果第一部分是真的,您只评估第二部分。例如:
1 | if (func1() && func2()) {func3();} |
是一样的
1 2 3 4 | if (func1()) { if (func2()) {func3();}} } |
这是必需的,因为func2()可能首先依赖于func1()为真。如果使用的&;和func1()的计算结果为false,则&;将以任何方式运行func2(),这可能导致运行时错误。
门外汉杰夫