首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么带逗号的三元运算符在真实情况下只计算一个表达式?

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

Stack Overflow用户
提问于 2017-11-29 02:52:15
回答 5查看 8.5K关注 0票数 119

我目前正在使用C++入门这本书学习C++,书中的练习之一是:

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

我们知道些什么?我们知道三元运算符比逗号运算符具有更高的优先级。对于二元运算符,这很容易理解,但对于三元运算符,我有点困难。使用二元运算符“具有更高的优先级”意味着我们可以使用括号将具有更高优先级的表达式括起来,并且它不会改变执行。

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

代码语言:javascript
复制
(someValue ? ++x, ++y : --x, --y)

这实际上导致了相同的代码,这不能帮助我理解编译器将如何对代码进行分组。

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

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

代码语言:javascript
复制
#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;
}

结果如下:

代码语言:javascript
复制
11 10

另一方面,使用someValue = false时,它会打印:

代码语言:javascript
复制
9 9

为什么C++编译器生成的代码对于三元运算符的真分支仅递增x,而对于三元运算符的假分支则同时递减xy

我甚至用括号将true-branch括起来,如下所示:

代码语言:javascript
复制
someValue ? (++x, ++y) : --x, --y;

但它仍然会导致11 10

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2017-11-29 03:18:55

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

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

逻辑或表达式?表达式:赋值-表达式

因此,我们有以下映射:

  • someValue:logical-or-expression
  • ++x, ++y:expression
  • ???是赋值表达式--x, --y还是仅为--x

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

这将导致三元(条件)表达式部分如下所示:

代码语言:javascript
复制
someValue?++x,++y:--x

从可读性的角度考虑,将++x,++y计算为带括号的(++x,++y)可能会有所帮助;?:之间的任何内容都将在条件之后进行排序。(在接下来的文章中,我将把它们括起来)。

并按以下顺序进行计算:

  1. someValue?
  2. (++x,++y)--x (取决于1的bool结果)

然后,该表达式被视为逗号运算符的左子表达式,右子表达式为--y,如下所示:

代码语言:javascript
复制
(someValue?(++x,++y):--x), --y;

这意味着左边是一个丢弃的值表达式,这意味着它肯定是被求值的,但是我们计算右边并返回它。

那么当someValuetrue时会发生什么呢?

  1. (someValue?(++x,++y):--x)执行并将xy递增为11,左侧表达式被丢弃(尽管递增的副作用仍然存在)
  2. 我们计算逗号运算符--y的右侧,然后将y递减返回be

为了“修复”这个行为,你可以用圆括号将表达式分组,把它转换成一个主表达式,这个表达式是一个赋值表达式*的有效条目。

代码语言:javascript
复制
someValue?++x,++y:(--x, --y);

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

赋值表达式-(可以包含) -->条件表达式-->逻辑或表达式-->逻辑与表达式-->包含或表达式-->异或表达式-->与表达式-->等式表达式-->关系表达式-->移位表达式-->加法表达式-->乘法表达式--> pm表达式-->强制转换表达式-->后缀表达式-->主表达式

票数 123
EN

Stack Overflow用户

发布于 2017-11-29 02:57:09

哇,这很棘手。

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

代码语言:javascript
复制
(someValue ? (++x, ++y) : --x), --y;

三元运算符需要一个:,它不能在该上下文中独立存在,但是在它之后,没有理由认为逗号应该属于false大小写。

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

如果someValue为false,则执行--x--y,将它们都减1。

票数 88
EN

Stack Overflow用户

发布于 2017-11-29 02:57:51

为什么C++编译器要为三元运算符的真分支生成仅递增x的代码

你曲解了所发生的事情。true-branch同时递增xy。但是,在此之后,y会立即无条件地递减。

这是如何实现的:从the conditional operator has higher precedence than comma operator in C++开始,编译器按如下方式解析表达式:

代码语言:javascript
复制
   (someValue ? ++x, ++y : --x), (--y);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^

注意逗号后面的“孤立”--y。这就是导致最初递增的y递减的原因。

我甚至用圆括号将

分支括起来,如下所示:

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

您在正确的路径上,但是您将错误的分支括起来:您可以通过将else分支括起来来解决这个问题,如下所示:

代码语言:javascript
复制
someValue ? ++x, ++y : (--x, --y);

Demo (prints 11 11)

票数 42
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47538906

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档