英文:
Bool in C# works something unclear for me
问题
以下是您要的翻译:
这里是一段C#代码示例。我不明白为什么在第一种情况下我们会得到1而不是0。
为什么它返回1呢?
static void Main(string[] args)
{
int firstNumber = 0;
bool simpleLogicResult = true & false & (firstNumber++ > 0);
Console.WriteLine($"firstNumber = {firstNumber}");
int secondNumber = 0;
bool shortCircuitResult = true && false && (secondNumber++ > 0);
Console.WriteLine($"secondNumber = {secondNumber}");
// 延迟
Console.ReadKey();
}
我期望得到0而不是1 :)
请注意,我已经将HTML实体字符(如&
和>
)翻译成对应的符号以便更好地理解原文。
英文:
Here goes an example of C# code. I did not get why in first case we will have 1 instead of 0.
Why does it return 1 instead?
static void Main(string[] args)
{
int firstNumber = 0;
bool simpleLogicResult = true & false & (firstNumber++ > 0);
Console.WriteLine($"firstNumber = {firstNumber}");
int secondNumber = 0;
bool shortCircuitResult = true && false && (secondNumber++ > 0);
Console.WriteLine($"secondNumber = {secondNumber}");
// Delay
Console.ReadKey();
}
I expect 0 instead of 1
答案1
得分: 3
以下是您要翻译的内容:
原因是 &
位运算符不会短路,而 &&
逻辑运算符会。正如您在变量名中所指出的,您至少意识到了这一点。
(不太清楚您是否了解后自增运算符 ++
的工作原理。它获取操作数的值(firstNumber
,值为 0
),将操作数递增,然后返回前自增的值。所以比较 > 0
在两种情况下都会得到假的结果,这可能与问题有关还可能不相关。)
编译器可以在编译期间评估所有的项,因为所有的值都是常量或已知的。它可以执行表达式简化,这确实发生了。
让我们看看您的前两行:
int firstNumber = 0;
bool simpleLogicResult = true & false & (firstNumber++ > 0);
这里发生了两件事。
首先,在第二行中的所有三个项都被编译,产生一组已知或常量值和一个递增操作。所有三个项都必须完全评估,包括所有副作用,因为 &
位运算符不会短路操作数。
其次,编译器执行表达式简化,尽可能地预先计算答案。由于计算中的所有项都是常量,因此可以在编译时预先计算表达式,而所有副作用(在这种情况下是递增操作)都被保留。
当您将编译后的 IL 反向转换为 C# 时,它会生成以下代码:
int firstNumber = 0;
firstNumber++;
bool simpleLogicResult = false;
现在,您的第二个计算使用了 &&
运算符:
int secondNumber = 0;
bool shortCircuitResult = true && false && (secondNumber++ > 0);
第一次操作 true && false
会产生一个常量假值,因此由于短路,第三个项不会被评估。因此,当编译器处理这个问题时,它不必将递增操作排队,就像对上面的算术操作一样。
所以在编译和反编译之后,我们得到以下代码:
int secondNumber = 0;
bool shortCircuitResult = false;
而且为了加分,前自增运算符 ++
在这个特定情况下会产生完全相同的结果,因为您在位运算 &
和逻辑运算 &&
表达式中都包含了一个 false
项。如果我们改变您的表达式,结果将不同:
int thirdNumber = 0;
bool result = true & (++thirdNumber > 0);
在这种情况下,生成的降级代码(从生成的 IL 反编译而来)是:
int thirdNumber = 0;
bool result = ++thirdNumber > 0;
遗憾的是,编译器似乎更难优化前自增,但结果是一样的:thirdNumber
是 1
,result
是 true
。
英文:
The base reason is that the &
bitwise operator does not short-circuit while the &&
logical operator does. As you've indicated in your variable names, you're at least aware of this fact.
(It's not so clear whether you understand how the post-increment ++
operator works. It fetches the value of the operand (firstNumber
, value: 0
), increments the operand, then returns the pre-increment value. So the comparison > 0
results in false in both cases. Which may or may not be germane to the question.)
The compiler can evaluate all of the terms during compilation because all of the values are either constant or well known. It is free to peform expression reduction, and that's exactly what actually happens.
Let's look at your first two lines:
int firstNumber = 0;
bool simpleLogicResult = true & false & (firstNumber++ > 0);
Two things are happening here.
The first is that all three terms in the second line are compiled, producing a set of known or constant values and an increment operation. All three must be full evaluated, including all side effects, because the &
bitwise operator does not short-circuit the operands.
Secondly, the compiler performs expression simplification, pre-calculating the answer as far as possible. Since all terms in the calculation are constant the expression can be pre-calculated at compile time, and all side effects (the increment operation in this case) are preserved.
What it produces, when you reverse the compiled IL back to C#, is this:
int firstNumber = 0;
firstNumber++;
bool simpleLogicResult = false;
Now, your second calculation uses the &&
operator:
int secondNumber = 0;
bool shortCircuitResult = true && false && (secondNumber++ > 0);
The first operation true && false
results in a constant false value, so the third term will not be evaluated due to short-circuiting. So when the compiler is working on this it doesn't have to queue the increment operation as it did for the arithmetic operation above.
So what we end up with after compilation and de-compilation is this:
int secondNumber = 0;
bool shortCircuitResult = false;
And for bonus points, the ++
<i>pre-</i>increment operator would produce the exact same results in this specific case, since you've included a false
term in the expression for both the bitwise &
and logical &&
expressions. If we change your expression though the results are different:
int thirdNumber = 0;
bool result = true & (++thirdNumber > 0);
In this case the resulting lowered code (decompiling from the generated IL) is:
int thirdNumber = 0;
bool result = ++thirdNumber > 0;
Sadly the pre-increment appears to be a little harder for the compiler to optimize, but the result is the same: thirdNumber
is 1
and result
is true
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论