意外结果,Gnu C 中的三元运算符

Posted

技术标签:

【中文标题】意外结果,Gnu C 中的三元运算符【英文标题】:Unexpected Result, Ternary Operator in Gnu C 【发布时间】:2012-04-03 13:02:51 【问题描述】:

所以C 中三元运算符的运算符优先级对我来说真的很奇怪。举个例子:

#include <stdio.h>

int main ()

   int i=5;
   int j=6;
   int k=7;
   printf("A: %d\n", i+j+(k!=7)?1:11); //prints 1
   printf("B: %d\n", i+j+((k!=7)?1:11)); //prints 22
   return 0;

这似乎类似于这里的问题:C++ ternary conditional and assignment operator precedenceTernary operator evaluation order

作为澄清,我知道括号使它起作用,正如我在原始帖子中指出的那样...

我只是想知道为什么语言作者会选择一种可能会欺骗人们的评估方法,而第一个语句似乎可以被编译器格式化为有效。

但这些问题涉及左侧或类成员内部的运算符,因为这种奇怪的行为发生在 RHS 上。

【问题讨论】:

这个故事的寓意:使用括号。 是的,发现这很困难,只是想知道为什么。 :) 对我来说,如果编译器看到 ? 为什么它不能在它之前使用任何东西,在 () 中使用更复杂的语句,或者在最简单的情况下是没有括号的单个语句......这似乎会让更有意义... Jason,大家都知道电脑是疯狂科学家在实验室里制造出来的,所以当然没有意义! 哈哈,我猜...希望这篇文章可以为某人省去一些麻烦。我犯了在大代码中尝试三元运算符的错误,它真的让我很头疼,试图找出我为什么会出现疯狂的段错误。 :) 嗯,一切都好,结局好! 【参考方案1】:

这里有什么奇怪的?第一部分解释为:

(11 + (k != 7)) ? 1 : 11

第二个被解释为

 11 + ((k !=7) ? 1 :11)

第一个是由优先规则引起的(二元算术的优先级高于三元运算符),第二个是通过用括号对表达式进行分组来规避优先规则。

您的编辑询问了原因,通常只能猜测这些原因,除非当时在场的 C 委员会中有人过来帮忙。我的猜测是,使用复杂表达式并要求其真值比使用三元运算符确定算术表达式的值更常见。想到这样的事情:

return (froble() + 3) == 0 ? 23 : 5; // parens for sanity but works without

如果这被解释为return (froble() + 3) == 5;,我真的会感到震惊。

【讨论】:

我明白了,但在我看来,优先规则会在他们第一次尝试三元组时烧毁很多人......对我来说(...)? 用于复杂操作,然后...? 用于单语句检查会更有意义,并且对那些第一次探索该语言的人更友好。 好吧,@pmr 是对的,但至少就既定惯例而言。一个有经验的 C 程序员很久以前就会训练他的眼睛将低优先级赋予 ?: 三元组,并且忽略条件周围的括号是公认的编程风格。 @JasonR.Mick 我尝试提供一个示例,说明您的解释会导致可怕的后果,并且将标准解释为更简洁的代码。 @pmr 很有趣,谢谢你的例子,我想从这个角度来看它可能是有道理的......【参考方案2】:

一个人应该选择一个非常高或非常低的优先级,其中一个或另一个会让做出错误假设的人感到惊讶。

选择低优先级的一个有用原因是它意味着运算符的功能类似于 if .. then .. else .. 没有任何大括号的构造,这可能意味着编译器编写者的工作量更少(他们可能使用相同的代码来处理两者),并由了解优先级的编码人员直接重构。

在实践中,该语言可能标准化了在标准化前时代编写的代码中最流行的优先级。

【讨论】:

以上是关于意外结果,Gnu C 中的三元运算符的主要内容,如果未能解决你的问题,请参考以下文章

在条件中使用三元运算符会产生意外的输出

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

PHP速记三元运算符“?:”解析错误意外“:”

三元表达式是啥?

使用 Python 的三元运算符与 lambda 组合的意外输出

Laravel Blade 中的三元组