Why '&&' and not '&'?

前端 未结 16 1460
别跟我提以往
别跟我提以往 2020-11-27 12:11

Why is && preferable to & and || preferable to |?

I asked someone who\'s been programming for years a

相关标签:
16条回答
  • 2020-11-27 12:53

    Simply,

    if exp1 && exp2

    if exp1 is flase don't check exp2

    but

    if exp1 & exp2

    if exp1 is false Or true check exp2

    and rarely people use & because they rarely want to check exp2 if exp1 is false

    0 讨论(0)
  • 2020-11-27 12:55

    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:

    a     = 00110010 (in decimal:    32+16+2   = 50)
    b     = 01010011 (in decimal: 64+   16+2+1 = 83)
    ----------------
    a & b = 00010010 (in decimal:       16+2   = 18)
    a | b = 01110011 (in decimal: 64+32+16+2+1 = 115)
    

    while a logical operator only works in bool:

    a      = true
    b      = false
    --------------
    a && b = false
    a || b = true
    

    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:

    if (person && person.punch()) {
        person.doVictoryDance()
    }
    

    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:

    if (person & person.punch()) {
        person.doVictoryDance()
    }
    

    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 if person is null. In fact, in this particular case, the second code would produce a null reference error if person is null, since it tries to call person.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.

    int CAN_PUNCH = 1 << 0, CAN_KICK = 1 << 1, CAN_DRINK = 1 << 2, CAN_SIT = 1 << 3,
        CAN_SHOOT_GUNS = 1 << 4, CAN_TALK = 1 << 5, CAN_SHOOT_CANNONS = 1 << 6;
    
    Person person;
    person.abilities = CAN_PUNCH | CAN_KICK | CAN_DRINK | CAN_SIT | CAN_SHOOT_GUNS;
    
    Place bar;
    bar.rules = CAN_DRINK | CAN_SIT | CAN_TALK;
    
    Place military;
    military.rules = CAN_SHOOT_CANNONS | CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT;
    
    CurrentLocation cloc1, cloc2;
    cloc1.usable_abilities = person_abilities & bar_rules;
    cloc2.usable_abilities = person_abilities & military_rules;
    
    // cloc1.usable_abilities will contain the bit pattern that matches `CAN_DRINK | CAN_SIT`
    // while cloc2.usable_abilities will contain the bit pattern that matches `CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT`
    

    Doing the same with logical operators would require an awkward amount of comparisons:

    Person person;
    person.can_punch = person.can_kick = person.can_drink = person.can_sit = person.can_shoot_guns = true;
    person.can_shoot_cannons = false;
    
    Place bar;
    bar.rules.can_drink = bar.rules.can_sit = bar.rules.can_talk = true;
    bar.rules.can_punch = bar.rules.can_kick = bar.rules.can_shoot_guns = bar.rules.can_shoot_cannons = false;
    
    Place military;
    military.rules.can_punch = military.rules.can_kick = military.rules.can_shoot_guns = military.rules.can_shoot_cannons = military.rules.can_sit = true;
    military.rules.can_drink = military.rules.can_talk = false;
    
    CurrentLocation cloc1;
    bool cloc1.usable_abilities.can_punch         = bar.rules.can_punch         && person.can_punch,
         cloc1.usable_abilities.can_kick          = bar.rules.can_kick          && person.can_kick,
         cloc1.usable_abilities.can_drink         = bar.rules.can_drink         && person.can_drink,
         cloc1.usable_abilities.can_sit           = bar.rules.can_sit           && person.can_sit,
         cloc1.usable_abilities.can_shoot_guns    = bar.rules.can_shoot_guns    && person.can_shoot_guns,
         cloc1.usable_abilities.can_shoot_cannons = bar.rules.can_shoot_cannons && person.can_shoot_cannons
         cloc1.usable_abilities.can_talk          = bar.rules.can_talk          && person.can_talk;
    
    bool cloc2.usable_abilities.can_punch         = military.rules.can_punch         && person.can_punch,
         cloc2.usable_abilities.can_kick          = military.rules.can_kick          && person.can_kick,
         cloc2.usable_abilities.can_drink         = military.rules.can_drink         && person.can_drink,
         cloc2.usable_abilities.can_sit           = military.rules.can_sit           && person.can_sit,
         cloc2.usable_abilities.can_shoot_guns    = military.rules.can_shoot_guns    && person.can_shoot_guns,
         cloc2.usable_abilities.can_talk          = military.rules.can_talk          && person.can_talk,
         cloc2.usable_abilities.can_shoot_cannons = military.rules.can_shoot_cannons && person.can_shoot_cannons;
    

    A classical example where bit-patterns and bitwise operator are used is in Unix/Linux file system permissions.

    0 讨论(0)
  • 2020-11-27 12:55

    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 &

    0 讨论(0)
  • 2020-11-27 12:56

    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.

    int a = 0; // 0 means all bits off
    a = a | 4; // set a to binary 100
    if ((a & 4) != 0) {
        // will do something
    }
    a = a & (~4) // turn bit off again, a is now 000
    

    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):

    if (foo() & bar()) {
        // do something
    }
    

    In C, if foo() returns 1 and bar() returns 2, the "something" won't be done because 1 & 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:

    if (foo() != 0 & bar() != 0) {
        // do something
    }
    
    0 讨论(0)
  • 2020-11-27 12:57

    In the case of:

    if (obj != null && obj.Property == true) { }
    

    would work as expected.

    But:

    if (obj != null & obj.Property == true) { }
    

    could potentially throw a null reference exception.

    0 讨论(0)
  • 2020-11-27 12:58

    Short and simple:

    1 && 2 = true
    because
    1 = true (non-zero) in C
    2 = true (non-zero) in C

    true ANDS logically with true to give true.

    But

    1 & 2 = 0 = false
    because
    1 = 0001 in binary
    2 = 0010 in binary

    0001 ANDs bitwise with 0010 to give 0000 = 0 in decimal.

    Likewise for || and | operators too...!

    0 讨论(0)
提交回复
热议问题