GCC三元条件运算符中的副作用与值计算?

GCC三元条件运算符中的副作用与值计算?,c,gcc,C,Gcc,我有以下代码,它会产生意想不到的结果: #include < stdio.h > int a = 0, value; int main(void) { // Testing the evaluation order of multiple // conditional operators: value = (a == 3) ? 3 : (a = 3) ? 5 : 0; printf("%d\n", value); return 0; }

我有以下代码,它会产生意想不到的结果:
 #include < stdio.h >

int a = 0, value;

int main(void)
{
    // Testing the evaluation order of multiple
    // conditional operators:
    value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
    printf("%d\n", value);

    return 0;
}
我希望这段代码打印3,因为条件运算符计算 从右到左,有一个序列点吗?第一个被执行的 操作,而它实际上打印5。 假设位于两个序列之间的表达式的副作用是错误的吗 当表达式的值为?时,也会计算点? 如果我添加printf%d\n a;但是我打印了3张,所以副作用就消除了。 或者只是控件确实传递给了其值为 首先是正式计算吗? 我更愿意押注于后者,因为将“a”的值改为3,并将右值 在将第二个条件赋值为4时,导致短路评估 对于第一个条件表达式,这意味着我得到了“a”和“value”的3。 我在Lubuntu 14.04和GCC 4.8.2上使用-std=c99标志获得了上述结果。
谢谢你帮我澄清这件事

让我们一次追踪这一部分。你有这样的表达:

value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
(a == 3) ? 3 : (a = 3) ? 5 : 0;
由于a从0开始,我们跳过第一个?的3个分支:然后看第二个分支,即

(a = 3) ? 5 : 0
这里的条件是a=3,它将a设置为3,然后计算为a的新值,即3。因为3不是零,所以我们取?的第一个分支,所以表达式的计算结果是5。净效果是a设置为3,值设置为5

语言规范保证求值顺序确实是您认为应该是的-除非条件按照它的方式运行,否则?:运算符的if和else分支保证不会执行,因此这里有序列点。我想你只是误解了a=3运算的效果


希望这有帮助

让我们一次追踪这一部分。你有这样的表达:

value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
(a == 3) ? 3 : (a = 3) ? 5 : 0;
由于a从0开始,我们跳过第一个?的3个分支:然后看第二个分支,即

(a = 3) ? 5 : 0
这里的条件是a=3,它将a设置为3,然后计算为a的新值,即3。因为3不是零,所以我们取?的第一个分支,所以表达式的计算结果是5。净效果是a设置为3,值设置为5

语言规范保证求值顺序确实是您认为应该是的-除非条件按照它的方式运行,否则?:运算符的if和else分支保证不会执行,因此这里有序列点。我想你只是误解了a=3运算的效果


希望这有帮助

条件运算符从左到右求值,在任一分支之前求值条件。您可能会将其与右关联性混淆,在右关联性中,它似乎从右向左绑定

条件表达式基本上会产生以下逻辑:

if(a == 3) {
    value = 3;
} else {
    if(a = 3) {
        value = 5;
    } else {
        value = 0;
    }
}

请注意,条件运算符在对条件求值之后才执行分支。

条件运算符从左到右求值,在对任一分支求值之前对条件求值。您可能会将其与右关联性混淆,在右关联性中,它似乎从右向左绑定

条件表达式基本上会产生以下逻辑:

if(a == 3) {
    value = 3;
} else {
    if(a = 3) {
        value = 5;
    } else {
        value = 0;
    }
}

请注意,在计算条件之后,条件运算符才会执行分支。

条件运算符不会从右向左计算。标准C11 6.5.15/4规定:

计算第一个操作数;在其之间有一个序列点 求值和第二个或第三个操作数的求值 以评估的为准。仅当 第一次比较不等于0;仅当 第一次比较等于0;结果是第二个或第二个的值 第三个操作数,以计算值为准

那么表达式a==3?3:a=3?5 : 0; 在以下步骤中进行评估:

a==3结果为0 a=3结果为3,不等于0 5. 所以5是赋值的

您可能会混淆如何计算条件运算符的概念以及条件运算符如何关联或组。C的语法指定表达式:

value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
(a == 3) ? 3 : (a = 3) ? 5 : 0;
关联或分组子表达式,如下所示:

((a == 3) ? 3 : ((a = 3) ? 5 : 0));

这通常被称为“合伙人权利”。但是,此分组/关联性并不影响表达式仍然从左到右求值,并且第二个条件表达式仅在“外部”条件表达式中的第一个操作数求值之后求值。

条件运算符不会从右到左求值。标准C11 6.5.15/4规定:

计算第一个操作数;在其之间有一个序列点 求值和第二个或第三个操作数的求值 以评估的为准。第二个操作数仅在 E 第一次比较不等于0;仅当 第一次比较等于0;结果是第二个或第二个的值 第三个操作数,以计算值为准

那么表达式a==3?3:a=3?5 : 0; 在以下步骤中进行评估:

a==3结果为0 a=3结果为3,不等于0 5. 所以5是赋值的

您可能会混淆如何计算条件运算符的概念以及条件运算符如何关联或组。C的语法指定表达式:

value = (a == 3) ? 3 : (a = 3) ? 5 : 0;
(a == 3) ? 3 : (a = 3) ? 5 : 0;
关联或分组子表达式,如下所示:

((a == 3) ? 3 : ((a = 3) ? 5 : 0));

这通常被称为“合伙人权利”。然而此分组/关联性不影响以下事实:表达式仍然从左到右求值,第二个条件表达式仅在“外部”条件表达式中的第一个操作数求值之后求值。

谁说条件运算符从右到左求值?谁说条件运算符从右到左求值从右到左计算?我明白了。因此,关联性不能确定将首先执行哪个操作。这是很难确定的,除非有一个复杂的表达式,有副作用,并在幸运的位置排序。每个表达式都是从左到右计算的吗?或者,除了标准规定的排序规则外,是否定义了订单执行?但是,一个操作符必须在某个地方得到一个值,因此,如果让我们说它的优先级低于另一个操作符的优先级,那么必须首先对它进行评估,以向另一个操作符提供一个值,对吗?标准说,除非稍后指定,否则子表达式的副作用和值计算是不排序的。正如您所说,如果子表达式的结果用于表达式的较大部分,则必须首先对其求值。然而,计算可能提前多少时间并不总是显而易见的,对于C语言来说,一般不要求表达式必须从左到右进行计算。还有关于副作用何时发生的问题,这些副作用是由序列点规则决定的。天哪!嗯,我知道副作用必须小心使用,但从更复杂的表达式中获取值似乎是一个彻头彻尾的混乱!我读过标准草案中关于评估的内容,但根据我的记忆,大部分内容都是以一种我无法理解的神秘方式写的。还有,因为它使用的术语我还没学过。非常感谢你的回答,如果我得到15个代表点,我将投票表决!在我看来,最好把副作用主要留给自己。编译器需要通过将副作用打包到更大的表达式中来进行优化的日子基本结束了。有时候,它可能是惯用的,比如*dst++=*src++,或者语法可能会迫使您将多个副作用塞进一个表达式中,比如for循环的控制子句,但在大多数情况下,实际上并不需要太多。我认为多个副作用表达式通常也会使代码更难理解。很抱歉再次打扰您,但我突然想到,我基本上不知道是什么导致了我意想不到的结果,所以我的问题与此无关。我认为将这个问题放在一个标题下会更有用,比如:求值顺序vs表达式分组或类似的东西。是否可以以非结构化或类似的方式关闭它,然后用另一个标题重新打开它?我一直在寻找它来了解更多关于这个话题的信息,但我找不到一条讨论这个话题的线索。我明白了。因此,关联性不能确定将首先执行哪个操作。这是很难确定的,除非有一个复杂的表达式,有副作用,并在幸运的位置排序。每个表达式都是从左到右计算的吗?或者,除了标准规定的排序规则外,是否定义了订单执行?但是,一个操作符必须在某个地方得到一个值,因此,如果让我们说它的优先级低于另一个操作符的优先级,那么必须首先对它进行评估,以向另一个操作符提供一个值,对吗?标准说,除非稍后指定,否则子表达式的副作用和值计算是不排序的。正如您所说,如果子表达式的结果用于表达式的较大部分,则必须首先对其求值。然而,计算可能提前多少时间并不总是显而易见的,对于C语言来说,一般不要求表达式必须从左到右进行计算。还有关于副作用何时发生的问题,这些副作用是由序列点规则决定的。天哪!嗯,我知道副作用必须小心使用,但从更复杂的表达式中获取值似乎是一个彻头彻尾的混乱!我读过标准草案中关于评估的内容,但根据我的记忆,大部分内容都是以一种神秘的方式写的,我只是
我不明白。还有,因为它使用的术语我还没学过。非常感谢你的回答,如果我得到15个代表点,我将投票表决!在我看来,最好把副作用主要留给自己。编译器需要通过将副作用打包到更大的表达式中来进行优化的日子基本结束了。有时候,它可能是惯用的,比如*dst++=*src++,或者语法可能会迫使您将多个副作用塞进一个表达式中,比如for循环的控制子句,但在大多数情况下,实际上并不需要太多。我认为多个副作用表达式通常也会使代码更难理解。很抱歉再次打扰您,但我突然想到,我基本上不知道是什么导致了我意想不到的结果,所以我的问题与此无关。我认为将这个问题放在一个标题下会更有用,比如:求值顺序vs表达式分组或类似的东西。是否可以以非结构化或类似的方式关闭它,然后用另一个标题重新打开它?我一直在寻找它来了解更多关于这个话题的信息,但我找不到一条讨论这个问题的线索。我认为评估与分组的顺序是这里的关键。我不认为我误解了a=3的效果,但我可能是错的,因为我刚开始学习编程。在第一个条件运算符生效之前,我希望操作返回true并将值3存储在a变量中。我的意思是,在非零值中计算为true,当然不是值true。a=3应该返回3…我认为评估与分组的顺序是这里的关键。我不认为我误解了a=3的效果,但我可能是错的,因为我刚开始学习编程。在第一个条件运算符生效之前,我希望操作返回true并将值3存储在a变量中。我的意思是,在非零值中计算为true,当然不是值true。a=3应该返回3…谢谢,我已经看过这个设置,但是没有按照零件的顺序执行。谢谢,我已经看过这个设置,但是没有按照零件的顺序执行。