循环条件中的三元运算符:评估顺序/操作。优先级不明确

Posted

技术标签:

【中文标题】循环条件中的三元运算符:评估顺序/操作。优先级不明确【英文标题】:Ternary operator in loop conditional: evaluation order / op. precedence unclear 【发布时间】:2019-06-05 07:10:46 【问题描述】:

编辑:

表达式“30 ? 4 : 1” 和 php 中非关联的含义?

已作为副本提供,但这涉及 PHP,而不是 C。

在为一个小程序构建一些测试用例时,我在其中引入了一个错误 for 循环的条件部分,如下所示:

for(int row = 0; row < (mode == TEST) ? NO_OF_TESTS : ROWS; row++)

(我知道应该将其从for 循环中拉出来,但这不会改变问题。)

这会通过超出数组的末尾作为 以上导致无限循环。

当然,修复很简单:

for(row = 0; row < ((mode == TEST) ? NO_OF_TESTS : ROWS); row++)
//                 ^                                   ^

但我对错误实现的行为方式更感兴趣。

这是一段完整的代码(本身没有意义,因为它是 脱离上下文,但它证明了问题)。

#include <stdio.h>
#include <stdlib.h>

#define TEST 0
#define INTERACTIVE 1

#define ROWS 2
#define NO_OF_TESTS 3
#define MAX_FRUIT_LEN 50

int main(void)

    char test_cases[NO_OF_TESTS][MAX_FRUIT_LEN] =
    "Orange",
     "Apple",
     "Pineapple";

    int mode = TEST;
    int row = 0;

    //This fails - but in a strange way
    //Uncomment this `for` loop and comment the other one to see the effects

    //for(int row = 0; row < (mode == TEST) ? NO_OF_TESTS : ROWS; row++)

    //With the parantheses, obviously, it works.
    for(row = 0; row < ((mode == TEST) ? NO_OF_TESTS : ROWS); row++)
    
        printf("Working:\tIn row %d: Mode: %d condition_eval: %d\n"
        , row , mode, row < ((mode == TEST) ? NO_OF_TESTS : ROWS));

        printf("Not Working:\tIn row %d: Mode: %d condition_eval: %d\n"
        , row, mode, row < (mode == TEST) ? NO_OF_TESTS : ROWS);

        printf("Row: %d \tFruit Name: %s\n",row, test_cases[row]);
    
    printf("\nTerminating conditional evaluation (at row %d):\n", row);

    printf("Working:\tIn row %d: Mode: %d condition_eval: %d\n"
    , row , mode, row < ((mode == TEST) ? NO_OF_TESTS : ROWS));

    printf("Not Working:\tIn row %d: Mode: %d condition_eval: %d\n"
    , row, mode, row < (mode == TEST) ? NO_OF_TESTS : ROWS);

    return 0;

查看输出和(错误的)条件

row < (mode == TEST) ? NO_OF_TESTS : ROWS

编译器似乎将其解释为:

   (row < (mode == TEST)) ? NO_OF_TESTS : ROWS
// ^                    ^

问题是:为什么?

这个表达式:

(mode == TEST)

可以被解释为&lt; 运算符的正确操作数,或者 ? 运算符的左操作数。 (但我猜不是同时两者。)

适用哪些规则?这是运算符优先级的问题吗?序列点是否起作用? 评估顺序是什么,为什么?

我很困惑;非常感谢任何帮助。

【问题讨论】:

@WernerHenze:不要考虑将 PHP 骗子链接到 C 问题。 PHP 家伙决定反转三元条件运算符的关联性! 不要在 for 循环的控制子句中编写 icky 运算符 goo,而是编写可读代码:int max = something; for(int row = 0; row&lt;max; row++) ... max = (mode == TEST) ? NO_OF_TESTS : ROWS "这是运算符优先级的问题吗?" 为什么不直接在任何 C 书籍中查找呢?例如这里:en.cppreference.com/w/c/language/operator_precedence @Lundin True。我实际上是在我原来的帖子里写的。没有更改代码,因为它对问题没有任何影响。 @Bathsheba 好点。那我们就拿这个吧:***.com/questions/25598884/… 【参考方案1】:

三元条件运算符的优先级较低。

所以

row < (mode == TEST) ? NO_OF_TESTS : ROWS

被分组为

(row < (mode == TEST)) ? NO_OF_TESTS : ROWS

人们喜欢根据运算符优先级表来思考,但实际上分组是硬连线到语言语法中的。

【讨论】:

您能详细说明一下分组吗?是什么决定了那些? (我知道&lt; 运算符的优先级更高。) @GermanNerd:语言语法可以。 C 语法相当简单——在 K & R 后面有一个很好的(但不是特别最新的)参考。 我确实看过那里——K&R 只是顺便提到了分组。在我看来,优先级实际上不是这里的问题,而只是分组。您能否指出 K&R 的一部分或制定分组规则的标准? K&R 甚至没有在其索引中列出它。 @Bathsheba 不,最大咀嚼是将源字符划分为预处理器标记。它与确定表达式的子表达式无关。 @Bathsheba 这基本上适用于具有相同优先级且所有左结合的二元运算符。但显然在1 + 1 * 1.0 中,+ 不能“咀嚼”下面的1。由于= 是右结合的,a = b = c 中的第一个= 也不能咀嚼b【参考方案2】:

问题是:为什么?

是运算符优先级的问题吗?

是的!

三元运算符的优先级相当危险,你不是第一个犯这个错误,我自己犯了

在表达式中保持安静的最好方法是添加 ()

【讨论】:

【参考方案3】:

是的,这是一个优先级问题 - 关系运算符(以及按位、逻辑、算术、一元和后缀运算符)的优先级高于三元运算符,因此表达式 a &lt; b ? c : d 被解析为 (a &lt; b) ? c : d .

如果最左边的表达式是a &amp;&amp; ba == ba * b 等,则相同。

【讨论】:

以上是关于循环条件中的三元运算符:评估顺序/操作。优先级不明确的主要内容,如果未能解决你的问题,请参考以下文章

javascript:使用三元运算符的意外评估行为

当 lhs 为假时,为啥在逻辑 AND 中评估条件(三元)运算符

Perl 三元条件运算符中的赋值问题

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

三元运算符既是左操作符又是右操作符..或两者都不是

Python中的三元运算符是如何实现的