条件运算符中使用的赋值语句

任何人都可以告诉我为什么这句话给出了错误 – Lvalue要求

(a>b?g=a:g=b); 

但这个是正确的

 (a>b?g=a:(g=b)); 

其中a , bg是整数变量, ab作为键盘的输入。

在表达中,

 (a > b ? g = a : g = b); 

关系运算符>具有最高优先级,因此a > b被分组为操作数。 条件表达式运算符? : ? :具有次高优先级。 它的第一个操作数是a>b ,第二个操作数是g = a 。 但是,条件表达式运算符的最后一个操作数被认为是g而不是g = b ,因为g这种出现与条件表达式运算符的绑定比对赋值运算符的绑定更接近 。 发生语法错误,因为= b没有左操作数(l值)。
您应该使用括号来防止此类错误,并生成更可读的代码,这些代码已在您的第二个语句中完成

 (a > b ? g = a : (g = b)); 

其中最后一个操作数g = b : ? 有一个l值g ,这就是为什么它是正确的。

或者你也可以

 g = a > b ? a : b 

表达方式:

 (a>b?g=a:g=b) 

解析为:

 (a>b?g=a:g)=b 

而且我们不能分配给表达式,因此它的l值错误。

阅读: C和C ++之间的条件运算符差异 Charles Bailey的答案:

#:语法如下:

 conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression 

这意味着a ? b : c = d a ? b : c = d解析为(a ? b : c) = d即使(由于’不是l值’规则),这也不会产生有效的表达式。

一面注意:

请在表达式中保留空格,以便它变得可读。

 (a>b?g=a:g=b); 

应该写成:

 (a > b? g = a: g = b); 

同样,你应该添加空格; 而且,

问题是运算符优先级 :在C中,三元条件运算符( ?: :)具有比赋值运算符( = )更高的优先级。

没有括号(这里没有做任何事情)你的表达式是这样的:

 a > b ? g = a : g = b; 

在那里具有最高优先级的运算符将是比较> ,因此这是您将获得第一个逻辑分组的位置:

 (a > b) ? g = a : g = b; 

下一个最高的表达式是三元条件,它产生以下表达式:

 ((a > b) ? (g = a) : (g)) = b; 

正如您所看到的,您现在将在赋值运算符的左侧最终得到一个左值(即值;而不是变量),这是不可行的。

正如您已经注意到的,解决方案是简单地将表达式分组。 我甚至会考虑这种良好的做法,特别是如果你不确定你的优先权会如何发挥作用。 如果您不想考虑它,请添加括号。 只需记住代码可读性,如果可以,请自行解决运算符优先级,以确保一切正确且可读。

至于可读性:我可能在这里使用经典的if()或者在三元条件之外移动赋值运算符,这通常是你定义max()

 g = a > b ? a : b; 

或者更通用的宏或内联函数:

 #define max(a, b) ((a) > (b) ? (a) : (b)) inline int max(int a, int b) { return a > b ? a : b; } 
 if(a>b) { g = a; } else { g = b; } 

可以用这个代替

 g = a > b ? a : b; //if a>b use the first (a) else use the second (b) 

您的表达式(a>b?g=a:g=b)被解析为:

 (a>b?g=a:g)=b // ^^^ 

从Microsoft文档 :

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

在C中,运算符?:具有更高的优先级 ,即operator = 。 那么这意味着( a ? b : c = d )将被解析为( a ? b : c ) = d 。 由于l值的规则,第一个表达式也是有效的,但没有按照你的想法行事。

要避免此错误,您还可以:

 g = ( a > b ) ? a : b; 

这个问题通常会触发一系列答案,试图通过运算符优先级的概念来解释这种情况。 实际上,它无法用这种方式解释,因为这是输入的典型示例,其中诸如“运算符优先级”的替代概念被破坏。 您可能知道,C中实际上没有“运算符优先级”。只有语法分组,通常无法通过运算符的任何线性排序来精确表达。

让我们来看看语言规范对它的看法。 在这种情况下,C语法的相关部分是?: operator和= operator的语法。 对于?:运算符是

 conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression 

对于=运算符,它是

 assignment-expression: conditional-expression unary-expression assignment-operator assignment-expression 

在第一种情况下,关键部分是?: operator的最后一个操作数:它不是expression ,而是conditional-expressionconditional-expression是C表达式语法的不同入口点:它在不再可能将top-level =运算符包含在conditional-expression中的位置“输入”语法。 将a =运算符“走私”到conditional-expression的唯一方法是将语法一直下降到最底层

 primary-expression: identifier constant string-literal ( expression ) generic-selection 

然后使用( expression )分支一直环绕到顶部。 这意味着conditional-expression只有在显式包装在(...)时才能包含=运算符。 例如,语法禁止你将g = b作为?:运算符的最后一个操作数。 如果你想要这样的东西,你必须明确括起来: ? : (g = b) ? : (g = b)

第二段语法存在一种非常类似的情况:赋值运算符。 赋值的左侧(LHS)是unary-expression 。 并且unary-expression “进入”C表达式的一般语法,其中包括顶级?:运算符为时已晚。 从unary-expression到达?:运算符的唯一方法是一直下降到primary-expression并获取( expression )分支。 这意味着语法禁止你有a > b ? g = a : g a > b ? g = a : g作为=运算符的LHS操作数。 如果你想要这样的东西,你必须明确地把它弄清楚: (a > b ? g = a : g) =

因此,“流行”的答案声称“运算符优先级”使语言将表达式解析为

 (a > b ? g = a : g) = b 

实际上是完全错误的。 实际上,正式C语法中没有派生树可以使您的输入符合C语言的语法。 您的输入根本无法解析。 这不是表达。 它在语法上是无效的。 C语言将其视为语法上的胡言乱语。

现在,在实践中,您可能会看到一些实现以“左值操作数分配所需的左值”诊断消息进行响应。 在forms上,这是一种误导性的诊断信息。 由于上面的输入不满足C语言表达式的语法,因此没有“赋值”,没有“左操作数”,也没有有意义的“左值”要求。

为什么编译器会发出这条奇怪的消息? 他们很可能确实将此输入解析为有效的C表达式

 (a > b ? g = a : g) = b 

?:的结果永远不是C中的左值,因此是错误。 但是,您对输入的这种解释是非标准(扩展?)行为,它在正式C语言中没有基础。 特定实现的这种行为可能是由于他们试图协调C和C ++语法(在这个领域有很大差异),尝试产生更易读(虽然“假”)错误消息或其他原因。

通常,在这样的实现中,在诸如输入的情况下也会弹出类似的问题

 a + b = 5 

将发出相同的错误,表明(a + b) = 5解析,而从迂腐的观点来看, a + b = 5根本不能解析为表达式(出于与上述相同的原因)。

同样,正式地说,这还不足以说编译器被“破坏”:编译器需要检测约束违规并发出一些诊断消息,这正是这里发生的事情。 诊断消息的文本没有正确反映问题的本质这一事实是无关紧要的(编译器可以简单地说“哈哈哈!”)。 但是这种误导性诊断的一个不良后果是它误导用户误解了问题,这是从这个问题的正式错误答案的抨击中痛苦地显而易见的。