Can I use bitwise operators instead of logical ones?

Bitwise operators work with bits, logical operators evaluate Boolean expressions. While expressions are returned to bool , why don't we use bitwise operators instead of a boolean?

In this example, I use bitwise rather than logical:

 #include <iostream> int main(){ int age; std::cin >> age; if( (age < 0) | (age > 100) ) // eg: -50: 1 | 0 = 1 std::cout << "Invalid age!" << std::endl; // if( (age < 0) || (age > 100) ) // std::cout << "Invalid age!" << std::endl; return 0; } 
+6
source share
5 answers

One possible answer: optimization . For instance:

 if ((age < 0) | (age > 100)) 

Suppose that age = -5 , there is no need to evaluate (age > 100) , since the first condition is fulfilled ( -5<0 ). However, the previous code will evaluate the expression (age > 100) , which is not required.

FROM

 if ((age < 0) || (age > 100)) 

Only the first part will be appreciated.

Note. . @Lundin mentioned in comments, sometimes | faster than || due to branching accuracy for the second option (and the problem of erroneous prediction). Therefore, in cases where another expression is so inexpensive | option may be faster. So the only way to find out in these cases is to check the code on the target platform.


The most important answer is to avoid undefined behavior and errors:

You can submit this code:

 int* int_ptr = nullptr; if ((int_ptr != nullptr) & (*int_ptr == 5)) 

This code contains undefined behavior . However, if you replace & with && , No undefined behavior no longer exists.

+10
source

You should not. Suppose you get two values ​​that only allow you to act if they are both nonzero.

 int b = foo(1); // returns 0x1 int c = foo(2); // returns 0x2 

The lower the following conditions will be: b && c == true , and b & c == 0

 if (b && c) { // This block will be entered } if (b & c) { // This block won't } 
+2
source

Even if you achieve the same result with the bit operator, it is better to use the logical operator here because of performance reasons.

In the expression (age < 0) || (age > 100) (age < 0) || (age > 100) second condition (age > 100) will be calculated only if (age < 0) is false . For such an expression, the compiler produces the code as follows:

 cmpl $0x0,-0x4(%rbp) js 1004010f9 <main+0x19> // <-- Skip right expr evaluation if left true cmpl $0x64,-0x4(%rbp) jle 100401100 <main+0x20> 

|| does not produce any additional branching in order to be able to skip the evaluation of the second expression.

+1
source

There is a clear difference between || and | .

Unlike most other operators in the language, the logical operator || explicitly sets the evaluation order. The first operand || must be rated before the second. The second one does not need to be evaluated at all.

This is fundamentally different from | , which behaves like most operators: the evaluation order is unspecified, and both expressions will be evaluated. Even if one operand is nonzero, the other operand will still be evaluated by side effects.

The value of this code is f1() || f2() f1() || f2() will always be evaluated using this pseudo-code:

 if(f1() != 0) { f2(); } 

whereas f1() | f2() f1() | f2() will perform both functions in an unspecified order that the programmer cannot know about.

It also means that expressions such as "|| are faster than |" naive. Of course, in the case of || the second operand is not necessarily evaluated, but this is due to the branch, as well as restrictions on how the compiler is allowed to override the expression. Which operator, which is usually faster, is not obvious.

+1
source

Answer: yes you can. The question is why do you want? I can name a few reasons why you should not:

  • This can be very confusing for other programmers.
  • It is easy to miss that one of the operands is not of type bool , which can lead to subtle errors.
  • The evaluation order of the operand is undefined.
  • This is contrary to the short circuit rule.

To illustrate the last point:

 bool f1() { cout << "f1" << endl; return true; } bool f2() { cout << "f2" << endl; return true; } int main() { if (f1() || f2()) { cout << "That was for ||" << endl; } if (f1() | f2()) { cout << "That was for |" << endl; } return 0; } 

He prints:

 f1 That was for || f1 f2 That was for | 

Assuming f2 could have significant side effects ( if (okToDestroyWorld && destroyWorld()) ... ), the difference could be huge. This would not surprise the Java programmer (where | and || are actually defined for Boolean languages ​​by the language specification), but this is not a common practice in C ++.

I can only think of one reason to use the bitwise operator for booleans: if you need XOR. There is no ^^ operator, so if (a ^ b) is fine if both a and b are equal to bool and there are no side effects.

0
source

Source: https://habr.com/ru/post/1011882/


All Articles