条件运算符的评估顺序

时间:2015-07-02 15:08:35

标签: c c11

众所周知,赋值=和条件?:运算符都具有正确的关联性。在以下代码示例中:

#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++部分),与赋值相反?

3 个答案:

答案 0 :(得分:6)

保证?:的评估顺序:首先计算第一个操作数,然后根据第一个操作数是否为真来计算第二个或第三个操作数。

您对运算符优先级/关联性评估顺序之间的关系感到困惑。他们扮演不同的角色。前者决定如何对运算符进行分组,而后者决定首先计算哪个子表达式。

考虑表达式a * b + c * d,优先规则意味着它等同于(a * b) + (c * d)。但是保证编译器会在a * b之前评估c * d吗?答案是否定的,在本例中,运营商+并不保证评估顺序。

条件运算符?:是具有指定评估顺序的少数运算符之一。 (其余为&&||,)。

在你的例子中

1 ? a++ : b ? c++ : d;
1 ? a++ : (b ? c++ : d);

始终是等效的,在两个表达式中,首先评估1,并且由于它是真的,接下来评估a++,结束。

答案 1 :(得分:3)

关联性优先级不定义评估顺序。这些概念完全不相关。 C中的评估顺序由排序规则定义,而不是由优先级或关联性定义。

a = b = c = d = 1; 关联确实是a = (b = (c = (d = 1)));,但这并不意味着应首先评估d = 1,尤其是在C语言中,赋值运算符求值为右值。

关联性只是说c应该收到转化为1类型的值d(“好像”它是从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)部分甚至没有触及。

答案 2 :(得分:1)

1 ? a++ : b ? c++ : d;

相当于

if (1) {
    a++;
}
else {
    if (b) {
        c++;
    }
    else {
        d;
    }
}

因此,输出将是

2 1 1 1