【问题标题】:What is wrong with this assignment in a conditional operator?条件运算符中的这个赋值有什么问题?
【发布时间】:2018-01-03 00:49:55
【问题描述】:

有一个错误。 在下面的代码中给 a[i] 赋值有错吗? 还是条件运算符有问题?

#include<stdio.h>
#include<string.h>
int main(){
  char a[12]="sumit tyagi";
  int i=0;
  while(a[i]!='\0'){ 
  a[i]>90 ? a[i]=a[i]-32 : a[i]=a[i]+32; //error in this line
  i++;
  } 
  printf("\n %s",a);

【问题讨论】:

  • 您可能对运算符优先级有疑问。你使用?:的方式有点奇怪。使用简单的ìf ... else... 声明可能会更好
  • a[i] = a[i]&gt;90 ? a[i]-32 : a[i]+32;
  • 不要滥用三元运算符。

标签: c compiler-errors variable-assignment conditional-operator lvalue


【解决方案1】:

a[i]&gt;90 ? a[i]=a[i]-32 : a[i]=a[i]+32;

评估为

a[i]&gt;90 ? (a[i]=a[i]-32) : (a[i]=a[i]+32);

因为= 的优先级低于?:。在标准 C 中你不能像上面那样写它,尽管一些编译器允许它作为扩展。

你可以把它写成更易读(和便携)

a[i] += a[i] > 90 ? -32 : +32;

【讨论】:

  • 好吧,天哪,现在你让我挂了。 :) 是故意错误还是只是在改进它时偶然犯了错误? (原来的编辑历史好像表现出不同的表情)如果是开玩笑的话,我不得不道歉:我不习惯在SE上看到无标记的讽刺,可能是因为可怜的新手可能从中学到了不好的东西.
  • @ilkkachu:再看一眼,表达式看起来不正确,看起来可能是负面的。多亏了你,我想我会解决的!
  • 我认为这可能是个好主意。谢谢你,我已经感到更安心了! :)
【解决方案2】:

这真的是理解conditional operator 的语法的问题。这在 C11 标准的 §6.5.15 中有详细说明:

条件表达式:
逻辑或表达式
逻辑或表达式?表达式:条件表达式

因此,条件运算符的第三个操作数必须是条件表达式。通过标准中定义的语法跟踪条件表达式的可能性,人们发现赋值表达式不是选项之一。相关语法定义见§6.5 Expressions

通过从conditional-expression一直到primary-expression的可能性链,可以看出一个conditional-expression em> 可以是 逻辑或表达式,或 逻辑与表达式,或 包含或表达式,或exclusive-OR-expression,或 AND-expression,或 equality-expression,或 relational-expression,或移位表达式,或加法表达式,或乘法表达式,或转换表达式 em>,或 unary-expression,或 postfix-expression,或 primary-expressionprimary-expression 是一个 identifier、一个 constant、一个 string-literal、一个 ( 表达式),或通用选择

因此,assignment-expression可能是一个条件表达式)不在条件表达式的可能性列表中。这就是问题中报错的原因:因为这里的赋值表达式不是有效的语法,语句:

a[i]>90 ? a[i]=a[i]-32 : a[i]=a[i]+32;

被解释为:

(a[i]>90 ? a[i]=a[i]-32 : a[i]) = a[i]+32;

上述赋值表达式的左侧不是可修改的左值,这是赋值表达式所要求的,因此会出错。

但是,请注意 ( expression ) 形式的括号表达式是一个有效的条件表达式 , assignment-expression 是一个表达式。所以,这是一个法律声明:

a[i]>90 ? a[i]=a[i]-32 : (a[i]=a[i]+32);

综上所述,这可能不是正确的编码方式。最好使用其他答案中提出的替代方案之一,例如:

a[i] += a[i] > 90 ? -32 : 32;

【讨论】:

  • 这确实是正确的。我将尝试更新我的答案以使其正确,仍然使用 cppreference.com 引用...
【解决方案3】:

这有点棘手。有一个很好的“有效”概述operator precedence in C,我会引用那里的注释来解释你的问题*):

语法中有一部分不能用优先表表示:赋值表达式不允许作为条件运算符的右手操作数,所以e = a &lt; d ? a++ : a = d是一个无法解析的表达式,因此条件和赋值运算符的相对优先级不容易描述。
但是,许多 C 编译器使用非标准表达式语法,其中 ?: 的优先级高于 =,后者将该表达式解析为 e = ( ((a &lt; d) ? (a++) : a) = d ),然后由于语义限制而无法编译:?: is never lvalue= 需要在左侧有一个可修改的lvalue

在 DavidBowling 在标准中的发现之后(感谢这项工作!),上面的第二段并不完全正确,或者至少有点令人困惑。 ?: 的右侧操作数不能是赋值是正确的,但中间操作数可以。因此,对于右侧,?:“优先于”=,而中间部分则不然。任何部分都可以是主表达式,因此附上“更改优先级”的工作方式与预期一样:

a[i]>90 ? a[i]=a[i]-32 : (a[i]=a[i]+32);

但是,正如其他人所说,这无论如何都是不必要的复杂,你可以实现你想要的

a[i] += a[i]>90 ? -32 : 32;

这也更容易理解。


*) 要理解此引文中的推理,您必须知道在 C 标准中使用 lvalue 来描述可能出现在 左侧 的内容(因此名称)分配(也可以分配给)。这是一个有点草率的定义,并在 C 标准中进一步澄清,我认为对于这个答案的上下文来说已经足够了。

【讨论】:

  • 对理论评估以及编译必然失败的原因进行了很好的分析:您注意到我不敢这样做。投赞成票。
  • 幸运的是,我找到了一个写得很好的来源来引用其中的棘手部分;)
  • 由于对语法的吸引力而已经投票;但进一步的挖掘向我揭示了a[i]&gt;90 ? (a[i]=a[i]-32) : (a[i]=a[i]+32); 实际上是合法的。我已经添加了一个包含相关细节的(希望是正确的)答案。
  • @DavidBowling 乍一看它绝对看起来正确!我会用标准仔细检查自己,这意味着 cppreference.com 确实在这里遗漏了一些东西。
【解决方案4】:

在您的语句中使用一次=,因为它的优先级低于?:。比如:

a[i] = a[i] &gt; 90 ? a[i] - 32 : a[i] + 32;

【讨论】:

    猜你喜欢
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 2020-09-08
    • 2012-08-31
    • 1970-01-01
    • 2011-03-11
    相关资源
    最近更新 更多