循环条件中的三元运算符:评估顺序/操作。优先级不明确
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)
可以被解释为<
运算符的正确操作数,或者
?
运算符的左操作数。 (但我猜不是同时两者。)
适用哪些规则?这是运算符优先级的问题吗?序列点是否起作用? 评估顺序是什么,为什么?
我很困惑;非常感谢任何帮助。
【问题讨论】:
@WernerHenze:不要考虑将 PHP 骗子链接到 C 问题。 PHP 家伙决定反转三元条件运算符的关联性! 不要在 for 循环的控制子句中编写 icky 运算符 goo,而是编写可读代码:int max = something; for(int row = 0; row<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
人们喜欢根据运算符优先级表来思考,但实际上分组是硬连线到语言语法中的。
【讨论】:
您能详细说明一下分组吗?是什么决定了那些? (我知道<
运算符的优先级更高。)
@GermanNerd:语言语法可以。 C 语法相当简单——在 K & R 后面有一个很好的(但不是特别最新的)参考。
我确实看过那里——K&R 只是顺便提到了分组。在我看来,优先级实际上不是这里的问题,而只是分组。您能否指出 K&R 的一部分或制定分组规则的标准? K&R 甚至没有在其索引中列出它。
@Bathsheba 不,最大咀嚼是将源字符划分为预处理器标记。它与确定表达式的子表达式无关。
@Bathsheba 这基本上适用于具有相同优先级且所有左结合的二元运算符。但显然在1 + 1 * 1.0
中,+
不能“咀嚼”下面的1
。由于=
是右结合的,a = b = c
中的第一个=
也不能咀嚼b
。【参考方案2】:
问题是:为什么?
是运算符优先级的问题吗?
是的!
三元运算符的优先级相当危险,你不是第一个犯这个错误,我自己犯了
在表达式中保持安静的最好方法是添加 ()
【讨论】:
【参考方案3】:是的,这是一个优先级问题 - 关系运算符(以及按位、逻辑、算术、一元和后缀运算符)的优先级高于三元运算符,因此表达式 a < b ? c : d
被解析为 (a < b) ? c : d
.
如果最左边的表达式是a && b
、a == b
、a * b
等,则相同。
【讨论】:
以上是关于循环条件中的三元运算符:评估顺序/操作。优先级不明确的主要内容,如果未能解决你的问题,请参考以下文章