`(i) = 1` 在标准 C 中是非法的吗?

Posted

技术标签:

【中文标题】`(i) = 1` 在标准 C 中是非法的吗?【英文标题】:Is `(i) = 1` illegal in standard C? 【发布时间】:2020-02-09 15:38:13 【问题描述】:

我正在编写一个遵循this standard 的 C 编译器,如果我解析这样的语句:

int i;
(i) = 1;

我的编译器会报告一个错误,指出(i) 是一个右值,不应赋值。

我检查了代码和规则,发现: 在赋值表达式语义中:

赋值运算符的左边应该有一个可修改的左值 操作数。

赋值表达式在 赋值,但不是左值。

在我的例子中,有两个赋值表达式: (i) = 1i 在括号中。所以(i) 应该是一个右值。

所以我的问题是: 是 (i) = 1 在这个 C 标准中非法?

【问题讨论】:

它仍然是一个左值,括号不会改变它。 大家好,如果合法,请指出标准中的哪个规则,我的编译器严格遵守规则。 括号中的 i 不是赋值表达式。赋值表达式并不意味着“赋值中涉及的表达式”或(i) 符合条件的任何其他内容。赋值表达式是assignments @user2357112 i是赋值表达式,AST树是EXPRESSION->ASSIGNMENT_EXPRESSION->CONDITIONAL_EXPRESSION->LOGICAL_OR_EXPRESSION->CAST_EXPRESSION->UNARY_EXPRESSION->POSTFIX_EXPRESSION->PRIMARY_EXPRESSION->IDENTIFIER > @reavenisadesk:assignment-expression 语法非终结符与赋值表达式不同。粗略地说,assignment-expression 是一个赋值表达式或任何具有更高优先级的东西。 【参考方案1】:

引用 n1570(发布前的最后一个 C11 标准草案):

6.5.1 主要表达方式(强调我的)

5 带括号的表达式是主表达式。 它的类型 和 value 与不带括号的表达式的相同。 它是左值、函数指示符或 void 表达式,如果 不带括号的表达式分别是一个左值、一个函数 指示符或空表达式。

i 是一个左值,因此根据上述情况,(i) 也是如此。为了回答您的问题,表达式 (i) = 1 是有效的 C。

【讨论】:

我有问题,我们看看括号主表达式的BNF:( expression ),所以类型和值与expression相同,而expressionassignment expression,而assignment expression 是一个primary expression,简单地说,i 最终会被视为assignment expression,所以它最终应该遵循assignment expression 的规则,所以它应该是一个右值,我想。 @reavenisadesk - 除了很清楚,白底黑字不是右值。还是说i = 1 也无效? 我认为i = 1是有效的,因为:assignment-expression: unary-expression assignment-operator assignment-expression,在i = 1的情况下,我被视为unary-expression,这是一个左值,而不是assignment expression,我想你i = 1例子不是这样的。 @reavenisadesk:语法没有说明什么是左值或右值。语义确实如此。对于赋值表达式,C 6.5.16 3(就在“语义”标题下)说的是赋值表达式(这是一个描述用赋值运算符形成的表达式的短语,而不是 assignment-expression,这是语法中的标记)不是左值。它没有说 assignment-expression 语法标记不是左值。 @reavenisadesk - 埃里克解释得比我更有说服力。此外,在我看来,您在这里不公正地选择(i)。关于语义的同一点适用于每一种类型的表达。【参考方案2】:

StoryTeller 已经在标准中解释了为什么对于您的示例,表达式 (i) 仍然是左值,但我相信您无缘无故地挂断了规范,所以请允许我尝试解决您的问题。

我检查了代码和规则,发现:in assignment 表达语义:

赋值运算符的左边应该有一个可修改的左值 操作数。

赋值表达式在 赋值,但不是左值。

整个引用是指整个赋值表达式,而不是 lhs 或 rhs。

“赋值运算符应该有一个可修改的左值作为它的左操作数。”声明 lhs 必须是可修改的左值。

“赋值表达式具有赋值后左操作数的值,但不是左值。”声明整个赋值表达式本身作为结果具有 lhs 的值并且它本身是一个右值。

所以以下都是正确的:

int i;
  i <- modifiable lvalue

(i) = 1;
  (i) <- modifiable lvalue (per StoryTeller's answer)
  1 <- rvalue
  ((i) = 1) <- rvalue

为什么这很重要?考虑以下几点:

int i = 0, j = 0, k = 0;
i = j = k = 1;
// parsed as `i = (j = (k = 1))`
// the expression `k = 1` has the value `1` and is an rvalue
// the expression `j = (k = 1)` has the value `1` and is an rvalue

(i = 2) = 3;
// is invalid, the expression `i = 2` is an rvalue, but it may not be the lhs of the assignment

在我的例子中,有两个赋值表达式:(i) = 1i in 括号。所以(i) 应该是一个右值。

不,这是不正确的。 (i) = 1 是唯一的赋值表达式。有两个子表达式(一个带括号的标识符(i) 和一个数字常量1)。

【讨论】:

【参考方案3】:

这个答案的灵感来自@Eric Postpischil。

assignment-expression 的产生是:

<assignment-expression> ::= <conditional-expression>
                          | <unary-expression> <assignment-operator> <assignment-expression>

在标准中,assignment expression 特定表示带有赋值运算符的表达式。所以:

<conditional-expression> is not an assignment expression
<unary-expression> <assignment-operator> <assignment-expression> is an assignment expresssion

所以规则:

赋值表达式在 赋值,但不是左值。

仅适用于生产&lt;unary-expression&gt; &lt;assignment-operator&gt; &lt;assignment-expression&gt;,不适用于&lt;conditional-expression&gt;

在示例 (i) =1 中,i&lt;assignment-expression&gt;,但不是 assignment expression,它是 &lt;conditional-expression&gt;,所以它是一个 lvaule,所以 (i) 是一个左值。

【讨论】:

以上是关于`(i) = 1` 在标准 C 中是非法的吗?的主要内容,如果未能解决你的问题,请参考以下文章

C语言是开源的吗?C++是开源的吗?C语言C++是两个开源的标准,而不是开源软件或其它

字符变量 [] = 0;和 char var[1];在C中是等价的吗?

指向未指定大小数组“(*p)[]”的指针在 C++ 中是非法的,但在 C 中是合法的

为啥指向未定义结构的指针有时在 C 和 C++ 中是非法的

如何在 C 中覆盖标准输出

+= 运算符在 Python 中是线程安全的吗?