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

时间:2013-07-28 08:04:48

标签: c

有人可以告诉我为什么这句话会出错 - Lvalue Required

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

但是这个是正确的

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

其中a , bg是整数变量,ab被视为来自键盘的输入。

6 个答案:

答案 0 :(得分:9)

在表达式中,

(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

答案 1 :(得分:8)

表达式:

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

解析为:

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

我们无法分配表达式,因此它的l值错误。

阅读:Conditional operator differences between C and C++ Charles Bailey的回答:

?:的语法如下:

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

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

一个注意:

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

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

应写成:

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

同样,您应该在;,之后添加空格。

答案 2 :(得分:4)

问题是operator precedence:在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;
}

答案 3 :(得分:1)

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

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

来自Microsoft documentation

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

在C中,运算符?:的运算符=precedence。然后,这意味着( a ? b : c = d )将被解析为( a ? b : c ) = d。由于l值的规则,第一个表达式也是有效的,但没有按照你的想法进行。

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

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

答案 4 :(得分:1)

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)

答案 5 :(得分:1)

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

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

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

并且=运算符是

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

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

conditional-expression

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

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

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

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

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

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

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

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

(a > b ? g = a : g) = b 的结果绝不是C中的左值,因此是错误。但是,您对输入的这种解释是非标准(扩展?)行为,它在正式C语言中没有基础。特定实现的这种行为可能是由于他们尝试协调C和C ++语法(在这方面有很大差异),尝试生成更易读(尽管是“假”)错误消息或其他原因。 / p>

通常,在这样的实现中,在诸如

的输入的情况下也会弹出类似的问题
?:

将发出相同的错误,建议使用a + b = 5 解析,而从迂腐的角度来看(a + b) = 5根本不能解析为表达式(原因与上述相同)。 / p>

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