C 中的短路和运算符优先级
Short circuit and operator precedence in C
我知道 C 中的逻辑运算符遵循短路,但我怀疑短路和运算符优先级规则是否相互对立。请参阅以下示例:
#include<stdio.h>
int main()
{
int a;
int b=5;
a=0 && --b;
printf("%d %d",a,b);
return 0;
}
根据优先级规则,前缀运算符的优先级最高。所以应该先计算 --b
,然后计算 &&
,最后将结果分配给 a
。所以预期的输出应该是 0 4
。但在这种情况下,&&
的第二个操作数从未实际执行,结果是 0 5
.
为什么这里没有应用优先规则。逻辑运算符是否不受优先规则约束?如果是,还有哪些其他运营商表现出这种行为?这种行为背后的逻辑是什么?
operator &&
的求值顺序是从左到右。
=
的优先级较低,实际上只有 ooperator ,
的优先级低于 =
.
所以表达式将读作 a = (0 && --b)
是 0 首先根据提到的评估顺序评估。
由于 0
的计算结果为 false
,因此无需计算表达式的第二部分,因为 false && true
是 false
,给定表达式的第一部分表达式为 false
,表达式将始终为 false
.
如果您有 ||
运算符,则必须计算表达式的第二部分。
优先级 影响歧义表达式的解析方式。当有多种方法可以用多个运算符解释一个表达式时,优先级会告诉我们哪种解释是正确的。将优先级视为一种找出隐含括号位置的机制。
例如,在所讨论的语句中,有两种有效的解析方法。如果 =
的优先级高于 &&
它可以读作:
(a = 0) && --b;
但由于&&
具有更高的优先级,它实际上被解释为:
a = (0 && --b);
(注意:您的代码格式表明它是第一个。注意不要误导!)
评估顺序与优先级不同。它们是相关但独立的概念。在使用优先级确定表达式的正确解析之后,评估顺序告诉我们评估操作数的顺序。它是从左到右吗?右到左?同时?未指定?
大部分评估顺序未指定。 +
和 *
和 <<
等运算符没有定义的评估顺序。编译器可以为所欲为,程序员不得编写依赖于任何特定顺序的代码。 a + b
可以评估 a
然后 b
,或者 b
然后 a
,或者它甚至可以交织他们的评估。
=
和 &&
等例外。 =
总是从右到左计算,&&
从左到右短路。
以下是对我们的声明进行逐步评估的方式:
a = (0 && --b)
、=
从右到左计算
0 && --b
, &&
评估从左到右短路
0
, 判断为 false 触发短路并取消下一步
--b
,短路未评估
- 结果是
0
a
,已计算变量引用
a = 0
,赋值发生,整体结果为0
You said that there is no specific order for +
and *
, but this table shows the order to be left to right. Why so?
table 的最后一列是关联性。当我们使用相同的运算符两次,或者当我们使用具有相同优先级的运算符时,结合性打破了优先级关系。
比如我们应该怎么读a / b / c
。是吗:
(a / b) / c
,或
a / (b / c)
?
根据table /
具有从左到右的结合性,所以是第一个
像 foo = bar = baz
这样的链式赋值呢?现在,赋值具有从右到左的关联性,因此正确的解析是 foo = (bar = baz)
.
如果这一切变得混乱,请关注一个简单的经验法则:
"Precedence and associativity are independent from order of evaluation."
运算符优先级并不一定表示表达式先执行,它只是表示表达式被解析为高优先级运算的结果用于低优先级运算,而不是相反大约。实际的表达式只有在需要时才会被评估!
您将两个相关但不同的主题混为一谈:运算符优先级和求值顺序。
运算符优先级规则规定了各种运算符如何组合在一起。在这个表达式的情况下:
a=0 && --b;
运算符分组如下:
a = (0 && (--b));
但这对操作数的计算顺序没有影响。&&
运算符特别规定首先计算左操作数,如果它的计算结果为 0,则不计算右操作数。
所以在这种情况下 &&
的左侧 0
被评估,因为它是 0 右侧 --b
不被评估,所以 b
不递增。
这是运算符优先级和求值顺序之间差异的另一个示例。
int val()
{
static x = 2;
x *= 2;
return x;
}
int main()
{
int result = val() + (5 * val());
printf("%d\n", result);
return 0;
}
上面的程序会打印什么?事实证明,有两种可能性,而且都是有效的。
在这个表达式中:
val() + (5 * val())
没有运算符具有任何类型的短路行为。因此编译器可以自由地以任何顺序评估 +
和 *
的各个操作数。
如果val()
的第一个实例首先被评估,结果将为4 + ( 5 * 8) == 44
。如果先计算 val()
的第二个实例,则结果将为 8 + (5 * 4) == 28
。同样,两者都是有效的,因为可以按任何顺序计算操作数。
运算符优先级并不是游戏中的全部。还有评估顺序。并且要求首先评估 a=0(评估顺序是从左到右),然后根本不评估 && 之后的右侧部分。
这就是 C 的工作原理。
我知道 C 中的逻辑运算符遵循短路,但我怀疑短路和运算符优先级规则是否相互对立。请参阅以下示例:
#include<stdio.h>
int main()
{
int a;
int b=5;
a=0 && --b;
printf("%d %d",a,b);
return 0;
}
根据优先级规则,前缀运算符的优先级最高。所以应该先计算 --b
,然后计算 &&
,最后将结果分配给 a
。所以预期的输出应该是 0 4
。但在这种情况下,&&
的第二个操作数从未实际执行,结果是 0 5
.
为什么这里没有应用优先规则。逻辑运算符是否不受优先规则约束?如果是,还有哪些其他运营商表现出这种行为?这种行为背后的逻辑是什么?
operator &&
的求值顺序是从左到右。
=
的优先级较低,实际上只有 ooperator ,
的优先级低于 =
.
所以表达式将读作 a = (0 && --b)
是 0 首先根据提到的评估顺序评估。
由于 0
的计算结果为 false
,因此无需计算表达式的第二部分,因为 false && true
是 false
,给定表达式的第一部分表达式为 false
,表达式将始终为 false
.
如果您有 ||
运算符,则必须计算表达式的第二部分。
优先级 影响歧义表达式的解析方式。当有多种方法可以用多个运算符解释一个表达式时,优先级会告诉我们哪种解释是正确的。将优先级视为一种找出隐含括号位置的机制。
例如,在所讨论的语句中,有两种有效的解析方法。如果 =
的优先级高于 &&
它可以读作:
(a = 0) && --b;
但由于&&
具有更高的优先级,它实际上被解释为:
a = (0 && --b);
(注意:您的代码格式表明它是第一个。注意不要误导!)
评估顺序与优先级不同。它们是相关但独立的概念。在使用优先级确定表达式的正确解析之后,评估顺序告诉我们评估操作数的顺序。它是从左到右吗?右到左?同时?未指定?
大部分评估顺序未指定。 +
和 *
和 <<
等运算符没有定义的评估顺序。编译器可以为所欲为,程序员不得编写依赖于任何特定顺序的代码。 a + b
可以评估 a
然后 b
,或者 b
然后 a
,或者它甚至可以交织他们的评估。
=
和 &&
等例外。 =
总是从右到左计算,&&
从左到右短路。
以下是对我们的声明进行逐步评估的方式:
a = (0 && --b)
、=
从右到左计算0 && --b
,&&
评估从左到右短路0
, 判断为 false 触发短路并取消下一步--b
,短路未评估- 结果是
0
a
,已计算变量引用a = 0
,赋值发生,整体结果为0
You said that there is no specific order for
+
and*
, but this table shows the order to be left to right. Why so?
table 的最后一列是关联性。当我们使用相同的运算符两次,或者当我们使用具有相同优先级的运算符时,结合性打破了优先级关系。
比如我们应该怎么读a / b / c
。是吗:
(a / b) / c
,或a / (b / c)
?
根据table /
具有从左到右的结合性,所以是第一个
像 foo = bar = baz
这样的链式赋值呢?现在,赋值具有从右到左的关联性,因此正确的解析是 foo = (bar = baz)
.
如果这一切变得混乱,请关注一个简单的经验法则:
"Precedence and associativity are independent from order of evaluation."
运算符优先级并不一定表示表达式先执行,它只是表示表达式被解析为高优先级运算的结果用于低优先级运算,而不是相反大约。实际的表达式只有在需要时才会被评估!
您将两个相关但不同的主题混为一谈:运算符优先级和求值顺序。
运算符优先级规则规定了各种运算符如何组合在一起。在这个表达式的情况下:
a=0 && --b;
运算符分组如下:
a = (0 && (--b));
但这对操作数的计算顺序没有影响。&&
运算符特别规定首先计算左操作数,如果它的计算结果为 0,则不计算右操作数。
所以在这种情况下 &&
的左侧 0
被评估,因为它是 0 右侧 --b
不被评估,所以 b
不递增。
这是运算符优先级和求值顺序之间差异的另一个示例。
int val()
{
static x = 2;
x *= 2;
return x;
}
int main()
{
int result = val() + (5 * val());
printf("%d\n", result);
return 0;
}
上面的程序会打印什么?事实证明,有两种可能性,而且都是有效的。
在这个表达式中:
val() + (5 * val())
没有运算符具有任何类型的短路行为。因此编译器可以自由地以任何顺序评估 +
和 *
的各个操作数。
如果val()
的第一个实例首先被评估,结果将为4 + ( 5 * 8) == 44
。如果先计算 val()
的第二个实例,则结果将为 8 + (5 * 4) == 28
。同样,两者都是有效的,因为可以按任何顺序计算操作数。
运算符优先级并不是游戏中的全部。还有评估顺序。并且要求首先评估 a=0(评估顺序是从左到右),然后根本不评估 && 之后的右侧部分。
这就是 C 的工作原理。