5

Can anybody please tell me why this statement is giving an error - Lvalue Required

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

but this one is correct

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

where a , b and g are integer variables , and a and b are taken as input from keyboard.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
john fedric
  • 167
  • 1
  • 11
  • 6
    Why not to use `g = a > b ? a : b`? – m0nhawk Jul 28 '13 at 08:12
  • @m0nhawk good point. But may be because OP come from c++. – Grijesh Chauhan Jul 28 '13 at 08:23
  • 1
    @m0nhawk: Wouldn't lead to such an interesting question. It's a rather nice case of easy to avoid mistakes you might not notice just by reading your code. I think it would even compile fine as C++, because `?:` and `=` got the same precedence there. Still doesn't mean you should necessarily do it, as it can cause confusion and "unexpected" behavior. – Mario Jul 28 '13 at 08:23

6 Answers6

9

In the expression,

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

the relational operator > has the highest precedence, so a > b is grouped as an operand. The conditional-expression operator ? : has the next-highest precedence. Its first operand is a>b, and its second operand is g = a. However, the last operand of the conditional-expression operator is considered to be g rather than g = b, since this occurrence of g binds more closely to the conditional-expression operator than it does to the assignment operator. A syntax error occurs because = b does not have a left-hand operand (l-value).
You should use parentheses to prevent errors of this kind and produce more readable code which has been done in your second statement

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

in which last operand g = b of : ? has an l-value g and thats why it is correct.

Alternatively you can do

g = a > b ? a : b
haccks
  • 104,019
  • 25
  • 176
  • 264
  • 1
    you explained with precedence that is better, actually grammar written using precedence rules. --high precedence operators should be added later such that the appear towards leaf node in evaluation tree. Got it?? – Grijesh Chauhan Jul 28 '13 at 08:41
  • @GrijeshChauhan; Please rephrase your sentence *high precedence operators should be added later such that the appear towards leaf node in evaluation tree*. I do not understand. – haccks Jul 28 '13 at 08:43
  • Read [this answer](http://stackoverflow.com/questions/17162919/unambiguous-grammar-for-exponentiation-operation/17170820#17170820) I explained how to arrange operators in grammars such that high precedence operators evaluate first--I think it will help perfectly. – Grijesh Chauhan Jul 28 '13 at 08:50
  • @GrijeshChauhan; I read that answer on the link you provided. This is just because of *Grammar*. – haccks Jul 28 '13 at 09:46
  • as recent discussion between me and Mario: I found `precedence(?:)` == `precedence(=)` so you added correct last link. – Grijesh Chauhan Jul 28 '13 at 10:03
  • @GrijeshChauhan; What about `a > b ? a++, b-- : a--, b++` ? – haccks Jul 28 '13 at 10:11
  • In C I think its same as `(a > b ? a++, b-- : a--), ( b++)` its valid in C -compiler will pass it. Correct na? – Grijesh Chauhan Jul 28 '13 at 10:15
  • @GrijeshChauhan; Read the answer given by [Jonathan Leffler](http://stackoverflow.com/a/12136188/2455888). – haccks Jul 28 '13 at 10:20
  • Yes that is what I commented to you... you know comma operator is hot question today? check list.. – Grijesh Chauhan Jul 28 '13 at 10:24
8

The expression:

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

parsed as:

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

And we can't assign to an expression so its l-value error.

Read: Conditional operator differences between C and C++ Charles Bailey's answer:

Grammar for ?: is as follows:

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

This means that a ? b : c = d parses as (a ? b : c) = d even though (due to the 'not an l-value' rule) this can't result in a valid expression.

One side note:

Please keep space in you expression so that it become readable for example.

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

Should be written as:

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

similarly, you should add space after ; and ,.

Community
  • 1
  • 1
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • Can you please explain me the reason – john fedric Jul 28 '13 at 08:07
  • @user2132128 "*lvalue*" is something that might appear on the left side. It is something that can be assigned. For example, you can't do `3 = x;`. – Maroun Jul 28 '13 at 08:09
  • @user2132128 The reason is that the grammar of the C language is defined like so. –  Jul 28 '13 at 08:10
  • 1
    @MarounMaroun "lvalue" is something that might appear on the left side" - **correct.** - "It is something that can be assigned" - **wrong.** Those are "modifiable lvalues". `const` objects and arrays are also lvalues, yet they cannot be assigned to. –  Jul 28 '13 at 08:11
  • 1
    @GrijeshChauhan I'm here to help :) (to help those who deserve it, anyway...) Eh, and take my upvote for making the effort quoting the CFG of the conditional operator! –  Jul 28 '13 at 08:13
  • 1
    @GrijeshChauhan; Coating standard or grammar is good practice but not a good idea in case of newbie. – haccks Jul 28 '13 at 08:38
  • @haccks I think you will love Mario's answer he explained with precedence that is much better. – Grijesh Chauhan Jul 28 '13 at 08:39
  • @haccks I can assure you it's the best (and the only correct) thing to do. Also, did you mean "quoting"? –  Jul 28 '13 at 14:43
  • @H2CO3; Oops! My bad :). Its "quoting", not "coating". – haccks Jul 28 '13 at 15:30
  • Charles Bailey's answer is completely incorrect in the parts where he talks about C grammar. Expression `a ? b : c = d` in not parsable in C at all. C grammar does not allow it to be parsed as `(a ? b : c) = d`. – AnT stands with Russia Jul 06 '17 at 00:32
4

The problem is operator precedence: In C the ternary conditional operator (?:) has a higher precedence than the assignment operator (=).

Without parenthesis (which don't do anything here) your expression would be this:

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

The operator with the highest precedence in there would be the comparison >, so this is where you'll get your first logical grouping:

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

The next highest expression is the ternary conditional, which results in the following expression:

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

As you can see, you'll now end up with an lvalue (i.e. a value; not a variable) on the left side of your assignment operator, something that won't work.

As you already noticed, the solution to this is to simply group the expressions on your own. I'd even consider this good practice, especially if you're unsure how your precedence might play out. If you don't want to think about it, add parenthesis. Just keep code readability in mind, so if you can, resolve the operator precedence on your own, to ensure you've got everything right and readable.

As for readability: I'd probably use a classic if() here or move the assignment operator outside the ternary conditional, which is how you usually define max():

g = a > b ? a : b;

Or more general as a macro or inline function:

#define max(a, b) ((a) > (b) ? (a) : (b))

inline int max(int a, int b) {
    return a > b ? a : b;
}
Mario
  • 35,726
  • 5
  • 62
  • 78
  • 1
    explaining using precedence is better approach for new guys! – Grijesh Chauhan Jul 28 '13 at 08:43
  • 1
    Mario but problem is this explanation is confusing if you think C/C++ together because according to [precedence in C++](http://en.cppreference.com/w/cpp/language/operator_precedence) also `precedence(?:)` > `precedence(=)` but `(a>b?g=a:g=b);` is a valid expression. – Grijesh Chauhan Jul 28 '13 at 08:57
  • +1 for the hint to move the `g =` entirely out of the conditional expression – Jens Gustedt Jul 28 '13 at 08:58
  • @GrijeshChauhan, the conditional operation in C++ is effectively working quite different from the one in C. But the question is entirely oriented C and not C++, so in the contrary I think it would be even more confusing to enter into the game of explaining the C++ approach. – Jens Gustedt Jul 28 '13 at 09:01
  • 1
    @JensGustedt Yes, but Mario is not new-guy so I can discuss with him, as I am explaining to hakssc also. Yes here both answered are better explained mine :) – Grijesh Chauhan Jul 28 '13 at 09:07
  • 1
    @GrijeshChauhan The precedence in C++ is different to C. Check the table again, both have `15`, which means they're evaluated right to left. Compare that table to the C one. The expression would work in C++, but it won't work in C. – Mario Jul 28 '13 at 09:56
  • 1
    @Mario Yes you are correct! I was incorrect... Read this [Order of Evaluation vs. Associativity](http://computer-programming-forum.com/47-c-language/8b2e279b1eb37018.htm) also a good read] – Grijesh Chauhan Jul 28 '13 at 10:01
1

Your expression (a>b?g=a:g=b) is parsed as :

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

From the Microsoft documentation :

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

In C, the operator ?: has an higher precedence that the operator =. Then it means that ( a ? b : c = d ) will be parsed as ( a ? b : c ) = d. Due to l-value's rule, the first expression is also valid but is not doing what you think.

To avoid this error, you can do also :

g = ( a > b ) ? a : b;
Pierre Fourgeaud
  • 14,290
  • 1
  • 38
  • 62
  • Please explain me the reason , why it is parsed as : (a>b?g=a:g)=b – john fedric Jul 28 '13 at 08:10
  • @user2132128 Again: the grammar of the C language defines it to be parsed like this. –  Jul 28 '13 at 08:12
  • Your link leads to C++ documentation and a grammar snippet is taken from C++ grammar. This question is about C language. C language grammar is significantly different from C++ language grammar in this specifc regard. It is not possible to parse the original expression in C grammar. – AnT stands with Russia Jul 06 '17 at 00:24
1
if(a>b)
{
    g = a;
}
else
{
    g = b;
}

that can be replaced with this

g = a > b ? a : b; //if a>b use the first (a) else use the second (b)
ahmedsafan86
  • 1,776
  • 1
  • 26
  • 49
1

This question usually triggers a barrage of answers trying to explain the situation through the concept of operator precedence. In reality it cannot be explained that way, since this is a typical example of an input, on which surrogate concepts like "operator precedence" break down. As you probably know, there's really no "operator precedence" in C. There are only grammatical groupings, which generally cannot be expressed precisely through any linear ordering of operators.

Let's take a look at what the language specification says about it. The relevant portions of C grammar in this case are the grammars of ?: operator and = operator. For ?: operator it is

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

and for the = operator it is

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

In the first case the critical part is the last operand of ?: operator: it is not an expression, but rather a conditional-expression. The conditional-expression is a different entry point into the grammar of C expression: it "enters" the grammar at the point where it is no longer possible to include a top-level = operator into a conditional-expression. The only way to "smuggle" a = operator into a conditional-expression is to descend the grammar all the way to the very bottom

primary-expression:
  identifier
  constant
  string-literal
  ( expression )
  generic-selection

and then wrap around all the way to the top using the ( expression ) branch. This means that a conditional-expression can contain a = operator only when it is explicitly wrapped in (...). E.g. the grammar prohibits you from having g = b as the last operand of ?: operator. If you want something like that, you have to explicitly parenthesize it: <smth> ? <smth> : (g = b).

A very similar situation exists with the second piece of grammar: assignment operator. The left-hand side (LHS) of assignment is unary-expression. And unary-expression "enters" the general grammar of C expression at the point where it is too late to include a top level ?: operator. The only way to reach the ?: operator from unary-expression is to descend all the way down to primary-expression and take the ( expression ) branch. This means that grammar prohibits you from having a > b ? g = a : g as the LHS operand of = operator. If you want something like that, you have to explicitly parentesize it: (a > b ? g = a : g) = <smth>.

For this reason "popular" answers claiming that "operator precedence" makes the language to parse your expression as

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

are actually completely incorrect. In reality, there's no derivation tree in formal C grammar that would make your input fit the syntax of C language. Your input is not parsable at all. It is not an expression. It is simply syntactically invalid. C language sees it as a syntactic gibberish.

Now, in practice you might see some implementations to respond with a "lvalue required as left operand of assignment" diagnostic message. Formally, this is a misleading diagnostic message. Since the above input does not satisfy the grammar of C language expression, there's no "assignment" in it, there's no "left operand" and there's no meaningful "lvalue" requirement.

Why do compilers issue this strange message? Most likely they do indeed parse this input as a valid C expression

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

The result of ?: is never an lvalue in C, hence the error. However, this interpretation of your input is non-standard (extended?) behavior, which has no basis in formal C language. This behavior of specific implementations might be caused by their attempts to reconcile C and C++ grammars (which are quite different in this area), by their attempts to produce a more readable (albeit "fake") error message or by some other reason.

Typically, in such implementations a similar issue also would pop up in case of inputs like

a + b = 5

The same error would be issued, suggesting a (a + b) = 5 parse, while from the pedantic point of view a + b = 5 is not parsable as an expression at all (for the same reasons as described above).

Again, formally, this is not enough to say that the compiler is "broken": the compiler is required to detect a constraint violation and issue some diagnostic message, which is exactly what happens here. The fact that the text of the diagnostic message does not correctly reflect the nature of the problem is inconsequential (the compiler can simply say "Ha ha ha!"). But one undesirable consequence of such misleading diagnostics is that it misleads users into misinterpreting the problem, which is BTW painfully evident from the barrage of formally incorrect answers posted to this question.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765