Is `(i) = 1` illegal in standard C?

229 Views Asked by At

I'm writing a C compiler which follows this standard, and if I parse statements like this:

int i;
(i) = 1;

my compiler will report an error which point out that (i) is a rvalue and should not be assignable.

I checked the code and the rules, and found this: in assignment expression semantics:

An assignment operator shall have a modifiable lvalue as its left operand.

An assignment expression has the value of the left operand after the assignment, but is not an lvalue.

In my case, the there are two assignment expressions: (i) = 1 and i in parentheses. So the (i) should be a rvalue.

So my question is: Is (i) = 1 illegal in this C standard?

3

There are 3 best solutions below

0
On BEST ANSWER

This answer is inspired by @Eric Postpischil.

the production of a assignment-expression is:

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

in the standard, the assignment expression specific means expressions with assignment operators. So:

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

so the rule:

An assignment expression has the value of the left operand after the assignment, but is not an lvalue.

only fits for production<unary-expression> <assignment-operator> <assignment-expression>, not for <conditional-expression>

in the example (i) =1, i is an <assignment-expression> but not an assignment expression, it is a <conditional-expression> so it is a lvaule so (i) is a lvalue.

0
On

StoryTeller explained already where in the standard why for your example, the expression (i) is still an lvalue, but I believe you are being hung up on the spec for no reason so allow me to try to address your concerns.

I checked the code and the rules, and found this: in assignment expression semantics:

An assignment operator shall have a modifiable lvalue as its left operand.

An assignment expression has the value of the left operand after the assignment, but is not an lvalue.

The entire quote is referring to the assignment expression as a whole, not the lhs or rhs.

"An assignment operator shall have a modifiable lvalue as its left operand." states that the lhs must be a modifiable lvalue.

"An assignment expression has the value of the left operand after the assignment, but is not an lvalue." states that the whole assignment expression itself as a result has the value of the lhs and is itself an rvalue.

So the following are all true:

int i;
  i <- modifiable lvalue

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

Why is this significant? Consider the following:

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

In my case, the there are two assignment expressions: (i) = 1 and i in parentheses. So the (i) should be a rvalue.

No that is incorrect. (i) = 1 is the only assignment expression. There are two subexpressions (one parenthesized identifier (i) and a numeric constant 1).

17
On

To quote n1570 (the last C11 standard draft prior to publication):

6.5.1 Primary expressions (emphasis mine)

5 A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression. It is an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or a void expression.

i is an lvalue, so per the above so is (i). And to answer your question, the expression (i) = 1 is valid C.