c++ 三值条件运算符和赋值运算符优先级

4xy9mtcn  于 2023-05-20  发布在  其他
关注(0)|答案(6)|浏览(196)

我对直接赋值和三元条件运算符优先级感到困惑:

#include<stdio.h>
int main(void)
{
    int j, k;

    j = k = 0;
    (1 ? j : k) = 1; // first
    printf("%d %d\n", j, k);

    j = k = 0;
    1 ? j : k = 1; // second
    printf("%d %d\n", j, k);
    return 0;
}

我希望输出为:
但它恰好是:
我还收到了这个警告:
主.cpp:20:警告:语句无效
也就是我说的第二行。
由于直接赋值运算符的优先级低于三元条件运算符,因此我希望注解为first和second的行是等效的。但事实并非如此。
我用g++ --version(Ubuntu 4.4.3- 4ubuntu 5)4.4.3尝试了这个

eulz3vhy

eulz3vhy1#

(1 ? j : k) = 1;

相当于,

if(true) j = 1;
else k = 1;

还有
相当于,

if(true) j;  // warning: statement has no effect
else k = 1;
x759pob2

x759pob22#

在第二种情况下,
被评估为:

(1) ? (j) : (k = 1);

由于计算结果为true,因此表达式的计算结果为j,它什么也不做。

jmo0nnb3

jmo0nnb33#

以前的答案解释了结果,但他们没有澄清疑问。我会试着给予我的理解如有错误,请指出来。
编译器可以如下分析和生成代码:

  • 将纯代码解析为树(代码纯文本->语义单元)。

原始代码分解为最小语义单元并格式化树。在这个过程中,编译器需要知道每个运算符的优先级。根据C++ operator precedence我们知道

  • ?:(条件运算符)与=(直接赋值运算符)具有相同的优先级,优先级= 16
  • 在此优先级(==16)中,结合性为右->左,因此k = 1高于?:

所以对于代码1 ? j : k = 1;,树可能是这样的:

op(?:)
      /         |          \
     /          |           \
  [condition] [true-branch] [false-branch]
      1           j             op(=)
                                /  \
                               k    1
  • 决定评估顺序(生成中间表示)

为了生成可运行的代码,编译器需要知道哪个部分应该首先eval(运行)。由Order of evaluation可知,对于?:算子,应先求[condition]的值,再根据条件结果求其值。它是简单的,并遵循我们的直觉。
所以想象一下最后运行的进程,1被eval为true,然后对true分支j进行评估,k = 1永远不会运行。
所以在知道了1,2之后,我们就知道了完整的原因。
如cpp文档所示,步骤1属于compile-time概念,而步骤2属于runtime概念。但从编译器的Angular 来看,它们都处于编译过程中,而compile-time/runtime的概念只是从语言设计的Angular 来看。

fbcarpbf

fbcarpbf4#

根据C++的优先级规则(https://en.cppreference.com/w/cpp/language/operator_precedence),
被评估 * 从右到左 *,即
[also请参阅链接中的注解2]。
这实际上没有效果,因为仅执行中间表达。

0tdrvxhp

0tdrvxhp5#

C/ C++ 中的运算符优先级不是由表或数字定义的,而是由语法定义的。以下是C++0x draft章节**5.16 Conditional operator [expr.cond]**中的条件运算符语法:

conditional-expression:
    logical-or-expression
    logical-or-expression ? expression : assignment-expression

因此,像this one这样的优先级表,当你在双冒号的左边使用赋值时是正确的,但当在右边使用时就不正确了。这种不对称的原因是什么,我不知道。这可能是一个历史原因:在C中,条件结果不是左值,因此给它赋值是没有意义的,允许赋值不带括号在当时看起来是明智的。

o2rvlv0m

o2rvlv0m6#

第二行相当于:
这与以下内容相同:

j;

这与以下内容相同:

;

关键是三元条件运算符的两个操作数可以是 expressions,因此运算符优先级在这里不相关。简单地说,第二个操作数是赋值表达式k = 1

相关问题