条件运算符的评估顺序
Order of evaluation for conditional operator
已知赋值运算符=
和条件运算符?:
都具有右结合性。在以下代码示例中:
#include <stdio.h>
int main(void)
{
int a, b, c, d;
a = b = c = d = 1;
1 ? a++ : b ? c++ : d;
printf("%d %d %d %d\n", a, b, c, d);
return 0;
}
作业:
a = b = c = d = 1;
相当于:
a = (b = (c = (d = 1)));
相应地:
1 ? a++ : b ? c++ : d;
等同于:
1 ? a++ : (b ? c++ : d);
标准对最后一个案例怎么说?它是否保证从左到右计算这样的组合表达式(因此不计算 c++
部分),就像赋值相反?
保证?:
的求值顺序:先求第一个操作数,然后根据第一个操作数是否为真求值第二个或第三个操作数。
你主要是对运算符precedence/associativity和求值顺序之间的关系感到困惑。他们扮演着不同的角色。前者决定运算符如何分组,而后者决定先评估哪个子表达式。
考虑表达式 a * b + c * d
,优先规则意味着它等同于 (a * b) + (c * d)
。但是是否保证编译器会在 c * d
之前评估 a * b
?答案是否定的,在此示例中,运算符 +
不保证计算顺序。
条件运算符 ?:
是为数不多的具有指定计算顺序的运算符之一。 (其余为 &&
、||
和 ,
)。
在你的例子中
1 ? a++ : b ? c++ : d;
1 ? a++ : (b ? c++ : d);
总是等价的,在两个表达式中,首先计算 1
,因为它为真,所以接下来计算 a++
,结束。
1 ? a++ : b ? c++ : d;
相当于
if (1) {
a++;
}
else {
if (b) {
c++;
}
else {
d;
}
}
所以,输出将是
2 1 1 1
关联性 和优先级 未定义求值顺序。这些概念完全不相关。 C 中的求值顺序由 顺序 规则定义,而不是由优先级或关联性定义。
确实 a = b = c = d = 1;
与 关联 为 a = (b = (c = (d = 1)));
,但这并不意味着应该首先评估 d = 1
,尤其是在 C 语言中,赋值运算符的计算结果为右值。
关联性只是说 c
应该接收值 1
转换为 d
的类型("as if" 它是从 d
读取的)。但这并不意味着 d = 1
应该首先完成。在您的示例中,所有变量都具有相同的类型,这意味着整个事物完全等同于 a = 1; b = 1; c = 1; d = 1;
绝对任何顺序。 a = b = c = d = 1
表达式中没有排序。
相同的逻辑适用于 ?:
运算符。它的结合性只是告诉您哪个操作数属于哪个运算符。而且分组确实是1 ? a++ : (b ? c++ : d);
。但是结合律并没有告诉你任何关于求值顺序的信息。 ?:
运算符中的评估顺序是单独且独立定义的:始终首先评估(排序)条件,然后评估一个(且仅一个)分支。在您的示例中,首先评估 1
,然后评估 a++
,其结果成为整个表达式的结果。 (b ? c++ : d)
部分甚至没有被触及。
已知赋值运算符=
和条件运算符?:
都具有右结合性。在以下代码示例中:
#include <stdio.h>
int main(void)
{
int a, b, c, d;
a = b = c = d = 1;
1 ? a++ : b ? c++ : d;
printf("%d %d %d %d\n", a, b, c, d);
return 0;
}
作业:
a = b = c = d = 1;
相当于:
a = (b = (c = (d = 1)));
相应地:
1 ? a++ : b ? c++ : d;
等同于:
1 ? a++ : (b ? c++ : d);
标准对最后一个案例怎么说?它是否保证从左到右计算这样的组合表达式(因此不计算 c++
部分),就像赋值相反?
保证?:
的求值顺序:先求第一个操作数,然后根据第一个操作数是否为真求值第二个或第三个操作数。
你主要是对运算符precedence/associativity和求值顺序之间的关系感到困惑。他们扮演着不同的角色。前者决定运算符如何分组,而后者决定先评估哪个子表达式。
考虑表达式 a * b + c * d
,优先规则意味着它等同于 (a * b) + (c * d)
。但是是否保证编译器会在 c * d
之前评估 a * b
?答案是否定的,在此示例中,运算符 +
不保证计算顺序。
条件运算符 ?:
是为数不多的具有指定计算顺序的运算符之一。 (其余为 &&
、||
和 ,
)。
在你的例子中
1 ? a++ : b ? c++ : d;
1 ? a++ : (b ? c++ : d);
总是等价的,在两个表达式中,首先计算 1
,因为它为真,所以接下来计算 a++
,结束。
1 ? a++ : b ? c++ : d;
相当于
if (1) {
a++;
}
else {
if (b) {
c++;
}
else {
d;
}
}
所以,输出将是
2 1 1 1
关联性 和优先级 未定义求值顺序。这些概念完全不相关。 C 中的求值顺序由 顺序 规则定义,而不是由优先级或关联性定义。
确实 a = b = c = d = 1;
与 关联 为 a = (b = (c = (d = 1)));
,但这并不意味着应该首先评估 d = 1
,尤其是在 C 语言中,赋值运算符的计算结果为右值。
关联性只是说 c
应该接收值 1
转换为 d
的类型("as if" 它是从 d
读取的)。但这并不意味着 d = 1
应该首先完成。在您的示例中,所有变量都具有相同的类型,这意味着整个事物完全等同于 a = 1; b = 1; c = 1; d = 1;
绝对任何顺序。 a = b = c = d = 1
表达式中没有排序。
相同的逻辑适用于 ?:
运算符。它的结合性只是告诉您哪个操作数属于哪个运算符。而且分组确实是1 ? a++ : (b ? c++ : d);
。但是结合律并没有告诉你任何关于求值顺序的信息。 ?:
运算符中的评估顺序是单独且独立定义的:始终首先评估(排序)条件,然后评估一个(且仅一个)分支。在您的示例中,首先评估 1
,然后评估 a++
,其结果成为整个表达式的结果。 (b ? c++ : d)
部分甚至没有被触及。