为什么带逗号的三元运算符仅在真实情况下评估一个表达式?

时间:2017-11-28 18:52:15

标签: c++ language-lawyer operator-precedence conditional-operator

我目前正在使用C ++ Primer一书学习C ++,本书的其中一个练习是:

  

解释以下表达式的作用:someValue ? ++x, ++y : --x, --y

我们知道什么?我们知道三元运算符的优先级高于逗号运算符。使用二元运算符这很容易理解,但是对于三元运算符,我有点挣扎。使用二元运算符"具有更高的优先级"意味着我们可以在具有更高优先级的表达式周围使用括号,并且不会更改执行。

对于三元运算符,我会这样做:

(someValue ? ++x, ++y : --x, --y)

有效地产生了相同的代码,这些代码无法帮助我理解编译器如何对代码进行分组。

然而,通过使用C ++编译器进行测试,我知道表达式编译,我不知道:运算符本身可以代表什么。所以编译器似乎正确地解释了三元运算符。

然后我以两种方式执行该程序:

#include <iostream>

int main()
{
    bool someValue = true;
    int x = 10, y = 10;

    someValue ? ++x, ++y : --x, --y;

    std::cout << x << " " << y << std::endl;
    return 0;
}

结果:

11 10

另一方面,someValue = false打印出来:

9 9

为什么C ++编译器生成的代码对于三元运算符的真分支仅增加x,而对于三元的假分支,它会减少x和{{1} }?

我甚至将括号括在真正的分支上,如下所示:

y

但仍然会产生someValue ? (++x, ++y) : --x, --y;

5 个答案:

答案 0 :(得分:121)

正如@Rakete在他们出色的回答中所说,这很棘手。我想稍微补充一下。

三元运算符必须具有以下形式:

  

logical-or-expression ? 表达式 : assignment-expression

所以我们有以下映射:

  • someValue logical-or-expression
  • ++x, ++y表达
  • ??? assignment-expression --x, --y或仅--x

实际上它只是--x因为赋值表达式不能被解析为用逗号分隔的两个表达式(根据C ++的语法规则),所以--x, --y不能视为赋值表达式

这导致三元(条件)表达式部分看起来像这样:

someValue?++x,++y:--x

为了便于阅读,可以考虑将++x,++y计算为,如果括号(++x,++y); ?之间包含的任何内容都将在条件之后排序。 (我会在帖子的其余部分用括号括起来。)

并按此顺序进行评估:

  1. :
  2. someValue?(++x,++y)(取决于--x 1的结果。)
  3. 然后将此表达式视为逗号运算符的左子表达式,右侧子表达式为bool,如下所示:

    --y

    这意味着左侧是废弃值表达式,这意味着它是明确评估的,但随后我们评估右侧并返回它。

    那么当(someValue?(++x,++y):--x), --y; someValue时会发生什么?

    1. true执行并将(someValue?(++x,++y):--x)x增加为y11
    2. 左表达式被丢弃(虽然增量的副作用仍然存在)
    3. 我们评估逗号运算符的右侧:11,然后将--y递减回y
    4. To&#34; fix&#34;在行为方面,您可以将10与括号分组,将其转换为主表达式,其中 赋值表达式的有效条目 *:

      --x, --y

      *这是一个相当有趣的长链,它将赋值表达式连接回主表达式:

      赋值表达式 ---(可以包含) - &gt; 条件表达式 - &gt; logical-or-expression - &gt; 逻辑与表达 - &gt; 包含或表达 - &gt; exclusive-or-expression - &gt; and-expression - &gt; equality-expression - &gt; relational-expression - &gt; shift-expression - &gt; additive-expression - &gt; 乘法表达式 - &gt; pm-expression - &gt; cast-expression - &gt; 一元表达 - &gt; postfix-expression - &gt; 基本表达式

答案 1 :(得分:87)

哇,这很棘手。

编译器将您的表达式视为:

(someValue ? (++x, ++y) : --x), --y;

三元运算符需要:,它不能在该上下文中独立存在,但在此之后,没有理由为什么逗号应属于错误情况。

现在,为什么你得到那个输出可能更有意义。如果someValue为真,那么++x++y--y会被执行,这不会有效地更改y,但会向x添加一个someValue

如果--x为false,则执行--yweb.xml,将它们减1。

答案 2 :(得分:42)

  

为什么C ++编译器会生成三元运算符的真分支只增加x

的代码

你误解了发生的事情。真分支增加xy。但是,y在此之后立即无条件地递减。

以下是这种情况:自the conditional operator has higher precedence than comma operator in C++以来,编译器按如下方式解析表达式:

   (someValue ? ++x, ++y : --x), (--y);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^

注意&#34;孤儿&#34;逗号后--y。这导致最初增加的y递减。

  

我甚至将括号括在真正的分支上,如下所示:

someValue ? (++x, ++y) : --x, --y;

你是在正确的道路上,但你把一个错误的分支括起来:你可以通过括号化else分支来解决这个问题,如下所示:

someValue ? ++x, ++y : (--x, --y);

Demo (prints 11 11)

答案 3 :(得分:5)

你的问题是三元表达式的优先级并不高于逗号。实际上,C ++不能简单地通过优先级来准确描述 - 它正是三元运算符和逗号分解之间的交互。

a ? b++, c++ : d++

被视为:

a ? (b++, c++) : d++

(逗号的行为就像它具有更高的优先级)。另一方面,

a ? b++ : c++, d++

被视为:

(a ? b++ : c++), d++

并且三元运算符具有更高的优先级。

答案 4 :(得分:2)

在答案中被忽略的一点(虽然涉及到评论)是条件运算符总是在实际代码中用于(设计意图?)作为将两个值中的一个赋值给变量的快捷方式。

所以,更大的背景是:

whatIreallyWanted = someValue ? ++x, ++y : --x, --y;

这是荒谬的,所以犯罪是多方面的:

  • 该语言允许在作业中产生荒谬的副作用。
  • 编译器没有警告你,你正在做一些奇怪的事情。
  • 这本书似乎专注于“技巧”问题。人们只能希望后面的答案是“这个表达的作用取决于一个人为的例子中的奇怪的边缘情况,以产生没人想要的副作用。永远不要这样做。”