`(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) = 1
和 i
在括号中。所以(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
相同,而expression
是assignment 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) = 1
和i
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
所以规则:
赋值表达式在 赋值,但不是左值。
仅适用于生产<unary-expression> <assignment-operator> <assignment-expression>
,不适用于<conditional-expression>
在示例 (i) =1
中,i
是 <assignment-expression>
,但不是 assignment expression
,它是 <conditional-expression>
,所以它是一个 lvaule,所以 (i)
是一个左值。
【讨论】:
以上是关于`(i) = 1` 在标准 C 中是非法的吗?的主要内容,如果未能解决你的问题,请参考以下文章
C语言是开源的吗?C++是开源的吗?C语言C++是两个开源的标准,而不是开源软件或其它
字符变量 [] = 0;和 char var[1];在C中是等价的吗?