int main (void)
{
int a = 5, b = 10, c;
c = a > 3 ? b = 5 : a = 3;
printf ("%d %d %d\n", a, b, c);
//cout << a << " " << b << " " << c << endl;
return 0;
}
Have a look at the above code, what will be the outcome if the code was in C language and if in C++ Language (replace with printf with cout)?
Directly going to the solution. Compilation error for C, and works perfect (no warnings) with C++. I saw this problem is a C question and answer book which didn’t bother to explain, so here is the explanation.
For C language, the compilation error is at line number 5 with the conditional statement. What some might have expected incorrectly is: first the a > 3 will be evaluated and if it is true then b = 5 will be evaluated, and the result of evaluation then is assigned to c. Or, if a > 3 is false then a = 3 will be evaluated and then the result will be assigned to c. This is incorrect.
In brief the answer is that the expression
c = a > 3 ? b = 5 : a = 3;
will be evaluated as
c = ((a > 3) ? (b = 5) : a) = 3;
In the above expression, the conditional expression will be evaluated first, because the conditional expression has higher operator precedence than the assignment operator. Next the second assignment operator will be evaluated first, because the equality operator has right-to-left associativity. Here lies the problem. The evaluation of the conditional expression is not an l-value, according to C99 Section 6.5.15 Paragraph 4 and footnote 95. First the conditional expression gets evaluated resulting a non-l-value, and next the second assignment gets evaluated, thus on the right hand side of the assignment operator there is a non-l-value therefore result in a compilation error.
If you use gcc to compiler, then you will get the error
conditional.c:7:25: error: lvalue required as left operand of assignment
On the other hand, C++ won’t complain. This is because C++ has a different set of rules, which leads c = a > 3 ? b = 5 : a = 3 to be interpreted as c = (a > 3) ? (b = 5) : (a = 3);. Related section from the standard is Section 5.16 which tells about the conditional expression in C++.
————————-
More Information about the C interpretation
Above I have assumed that the expression in the code will be evaluated as
c = ((a > 3) ? (b = 5) : a) = 3;
Why? And why not as follows ?
c = (a > 3) ? (b = 5) : (a = 3);
To answer this in one line, in C language, there are no grammer rules which leads the interpretation of the expression c = a > 3 ? b = 5 : a = 3; as c = (a > 3) ? (b = 5) : (a = 3);. Why? For that we need to dig deep into the standards and have a look at the production rules.
————————-
C99 Section 6.5.15 Paragraph 1
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
and
C99 Section 6.5.16 Paragraph 1
assignment-expression:
conditional-expression
unary-expression assignment-operator assignment-expression
assignment-operator: =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
The third operand of the ? : operator is a conditional-expression. If you expand it using the defined production rules, you will never reach an expression a = b. On the other hand the second operand is an expression, if you expand the second operand, an expression, may lead you to an assignment operation.
I am quoting the production rules for C language below. Try to trace it.
C99 Section 6.5.14 Paragraph 1
logical-OR-expression:
logical-AND-expression
logical-OR-expression || logical-AND-expression
C99 Section 6.5.13 Paragraph 1
logical-AND-expression:
inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression
C99 Section 6.5.12 Paragraph 1
inclusive-OR-expression:
exclusive-OR-expression
inclusive-OR-expression | exclusive-OR-expression
C99 Section 6.5.11 Paragraph 1
exclusive-OR-expression:
AND-expression
exclusive-OR-expression ^ AND-expression
C99 Section 6.5.10 Paragraph 1
AND-expression:
equality-expression
AND-expression & equality-expression
C99 Section 6.5.9 Paragraph 1
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
C99 Section 6.5.8 Paragraph 1
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
C99 Section 6.5.7 Paragraph 1
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
C99 Section 6.5.6 Paragraph 1
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
C99 Section 6.5.5 Paragraph 1
multiplicative-expression:
cast-expression
multiplicative-expression * cast-expression
multiplicative-expression / cast-expression
multiplicative-expression % cast-expression
C99 Section 6.5.4 Paragraph 1
cast-expression:
unary-expression
( type-name ) cast-expression
C99 Section 6.5.3 Paragraph 1
unary-expression:
postfix-expression
++ unary-expression
-- unary-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-name )
unary-operator: &, *, +, -, ~, !
C99 Section 6.5.2 Paragraph 1
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( argument-expression-list_opt )
postfix-expression . identifier
postfix-expression -> identifier
postfix-expression ++
postfix-expression --
( type-name ) { initializer-list }
( type-name ) { initializer-list , }
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
C99 Section 6.5.1 Paragraph 1
primary-expression:
identifier
constant
string-literal
( expression )
—————————-
More information about the C++ interpretation
In C++
c = a > 3 ? b = 5 : a = 3;
will be interpreted as below
c = (a > 3) ? (b = 5) : (a = 3);
This is because C++ production rules are different than the C production rules.
C++ Section 5.16
conditional-expression:
logical-or-expression
logical-or-expression ? expression : assignment-expression
Note that the production rules for the conditional-expression is different in C++ when compared to C language.
I am also listing the required production rules in C++ and then using the rules I will derive that we can parse the last expression as (a = b).
C++ Section 5.17
assignment-expression:
conditional-expression
logical-or-expression assignment-operator assignment-expression
throw-expression
assignment-operator:
=, *=, /=, %=, +=, -=, >>=, <<=, &=, ^=, |=
C++ Section 5.18
expression:
assignment-expression
expression , assignment-expression
C++ Section 5.15
logical-or-expression:
logical-and-expression
logical-and-expression || logical-and-expression
C++ Section 5.14
logical-and-expression:
inclusive-or-expression
logical-and-expression && inclusive-or-expression
C++ Section 5.13
inclusive-or-expression:
exclusive-or-expression
inclusive-or-expression | exclusive-or-expression
C++ Section 5.12
exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression
C++ Section 5.11
and-expression:
equality-expression
and-expression & equality-expression
C++ Section 5.10
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
C++ Section 5.9
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
C++ Section 5.8
shift-expression
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
C++ Section 5.7
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
C++ Section 5.6
multiplicative-expression:
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
multiplicative-expression % pm-expression
C++ Section 5.5
pm-expression:
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression
C++ Section 5.4
cast-expression:
unary-expression
( type-id ) cast-expression
C++ Section 5.3
unary-expression:
postfix-expression
++ cast-expression
-- cast-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-id )
new-expression
delete-expression
unary-operator: one of
* & + - ! ~
C++ Section 5.2
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( expression-list )
simple-type-specifier ( expression-list )
typename :: nested-name-specifier identifier ( expression-list )
typename :: nested-name-specifier template identifier ( expression-list )
postfix-expression . template id-expression
postfix-expression -> template id-expression
postfix-expression . pseudo-destructor-name
postfix-expression -> pseudo-destructor-name
postfix-expression ++
postfix-expression --
dynamic_cast < type-id > ( expression )
static_cast < type-id > ( expression )
reinterpret_cast <type-id> ( expression )
const_cast < type-id > ( expression )
typeid ( expression )
typeid ( expression )
expression-list:
assigned-expression
expression-list , assignment-expression
pseudo-destructor-name:
:: nested-name-specifier type_name :: ~ typename
:: nested-name-specifier template type_name :: ~ typename
:: nested-name-specifier ~ typename
C++ Section 5.1
primary-expression:
literal
this
( expression )
id-expression
id-expression:
unqualified-id
qualified-id
unqualified-id:
identifier
operator-function-id
conversion-function-id
~class-name
template-id
C++ Section 2.13
literal:
integer-literal
character-literal
floating-literal
string-literal
string-literal
boolean-literal
conditional-expression
|
V
logical-or-expression ? expression : assignment-expression
|
|
+---------------+
|
V
logical-or-expression assignment-operator assignment-expression
| | |
V V V
inclusive-or-expression = conditional-expression
| |
V V
exclusive-or-expression logical-or-expression
| |
V V
and-expression inclusive-or-expression
| |
V V
equality-expression exclusive-or-expression
| |
V V
relational-expression and-expression
| |
V V
shift-expression equality-expression
| |
V V
additive-expression relational-expression
| |
V V
multiplicative-expression shift-expression
| |
V V
pm-expression additive-expression
| |
V V
cast-expression multiplicative-expression
| |
V V
unary-expression pm-expression
| |
V V
postfix-expression cast-expression
| |
V V
primary-expression unary-expression
| |
V V
id-expression postfix-expression
| |
V V
unqualified-id primary-expression
| |
V V
identifier literal
| |
V V
a integer-literal
|
V
.
.
s o m e m o r e
e x p a n s i o n s
s e c 2.13
.
.
|
V
3
Sorry for listing long production rules quoted from the standards, I have tried to keep the required rules at hand so that you can trace them.

Nice article!
Since I use both C and C++, I often tends to put parenthesis to clarify and to be able to use code both in C++ and C context.
(You need to correct the first formula in “More about C++…”. I think you mean the initial one)
Hey!
Same here, I always use parenthesis whenever there is a confusion, or even when no confusion for clarity and easier reading.
Thanks for pointing out the error. One of the drawbacks of copy paste :) .
There is a funny spin on this, that is not directly related:
#include <stdio.h> int main(void) { int a = 5, b = 10, c; c = (a > 3) ? (3, b = 5, 10) : (4, a = 3); printf ("%d %d %d\n", a, b, c); return 0; }Some time ago some compilers had some difficulties with what to return after a parenthesis, and a construction with “,” was needed to make it clear.
Code looks interesting. Can you elaborate what you want to point out in this code? What I understand is that the left operands of the comma operator won’t be the result of the evaluation. Are you saying that previously some compiler had problems parsing the comma operator expression without the parenthesis?
And I have merged your comment into one.
Early 90:s I worked with more or less compliant cross compilers.
Those didn’t always return 5 if you had the expression (a=5). Especially if you made more complex operations inside brackets, like lets say (a = b+c*4). In this last case I needed to clarify with (a = b+c*4, a), to really be sure to use a.
Oh, that’s a pretty interesting information. Thanks for sharing it
Your explanation of the topic is really helpful. :)
Thanks for stopping by! I am glad to know you liked the post.