質問

I was recently asked this question in an interview which I totally got wrong but got me curious about the compiler optimizations in C# and .net

Consider the following snippet:

void Main()
{
    Console.WriteLine("Results when bitwise or is used: ");
    Console.WriteLine(FuncA() | FuncB());

    Console.WriteLine("Results when or operator is used: ");
    Console.WriteLine(FuncA() || FuncB()); 
}

bool FuncA()
{
    Console.WriteLine("Function A is executing.");
    return true;
}

bool FuncB()
{
    Console.WriteLine("Function B is executing.");
    return false;
}

Running the above results gets me following result:

Results when bitwise or is used:

Function A is executing.

Function B is executing.

True

Results when or operator is used:

Function A is executing.

True

My question here is why did the complier did not optimize when the bitwise operator is used? Just as for the C# or operator the parameters are already known to the compiler then why wouldn’t it handle it the same way for the bitwise or?

役に立ちましたか?

解決 4

The && and || operators use an early-exit strategy specifically to prevent the side-effects of the right-hand term.

This (slightly modified) C example from the Wikipedia page 280Z28 linked shows an example of where this is useful:

int denom = 0;
if (denom && num/denom) {
    do_something();
}

In this case, early exit from evaluation of the terms means that the program will not throw a divide-by-zero error while evaluating the condition, which is A Good Thing.

Conversely the bit-wise operators are defined by the language specification to evaluate both terms, including all side effects, before performing the operation on them.

One way of thinking about this is to consider the bit-wise operators as eager and the logical operators as lazy with regard to their evaluations. Eager operators will evaluate all of their operands before continuing, lazy operators will consider the operands in sequence and exit early if possible.

Incidentally, the (hypothetical) ^^ operator cannot exit without evaluating both operands, since the result cannot be determined by a specific value of one operand as is the case with && and ||.

他のヒント

Edit: Updated terminology for consistency with ECMA-334 (C# language specification). References (e.g. §14.10) are to specific sections of ECMA-334.

Logical operators (|, &, ^) are not short-circuiting in C# (§14.10). This means all of the operands will be evaluated even if the final result of the expression is uniquely determined by a subset of the operands. The fact that these operators are not short-circuiting is not explicitly stated in the language specification, but is implied by the way signatures are presented. The operands for these operators are evaluated as though they are being passed in a method call, i.e. left-to-right and not short-circuited.

bool operator &(bool x, bool y);
bool operator |(bool x, bool y);
bool operator ^(bool x, bool y);

Conditional logical operators (||, &&) on the other hand are short-circuiting (§14.11).

The behavior is defined in the language specification (standard ECMA-334), and was likely chosen for its consistency with earlier programming languages (C++, Java).

That's not optimization - it's a fundamental property of the && and || operators, known as short-circuiting.

The theory behind short-circuiting is that some values of the left operand mean we don't have to test the right operand. With &&, when the left side is false, the expression as a whole cannot possibly be true, so there is no point evaluating the right side. With ||, the right side is irrelevant when the left side is true.

The bitwise operators |, &, ^ don't short-circuit - both of their operands must be evaluated to know the result for sure.

The bitwise operator does not optimize because it is used when the entire width of the result is desired. In essence, it is defined to not be optimized.

In contrast the OR operator is defined to determine if either operand is true.

Another way to consider it is that the OR operator (||) is a Boolean operator, which is optimizable, while the bitwise operator (|) is not a Boolean operator, so cannot be short-circuited.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top