Pyranth
Pyranth

Reputation: 135

Using increment in ternary operator in C

For the example, after I use

int a = 5, b = 6;
x = (a < b) ? a++ : b++;

x gets the value of a, which is 5, and a increments to 6, which is expected.

When I use

a = (a < b) ? a++ : b++;

After this line, a still remains 5.

But

a = (a++ < b++) ? a : b;

a is now 6.

Why is this happening and why isn't increment operator executed in the first case?

EDIT: Just to clarify, I'm asking why this happens when I'm using these lines separately, one by one, not all three in the same time.

Upvotes: 9

Views: 5061

Answers (4)

Mukit09
Mukit09

Reputation: 3409

a = (a < b) ? a++ : b++;

here, we stored a in a, and then incremented it. But it is like

a = a++; // as a<b

which shows undefined behaviour.

a = (a++ < b++) ? a : b;

here, a is being incremented at the time of comparison, so now a is 6, which is stored in a.

Upvotes: 4

John Bode
John Bode

Reputation: 123578

From the horse's mouth:

6.5 Expressions
...
2 If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.84)
84) This paragraph renders undefined statement expressions such as
    i = ++i + 1;
    a[i++] = i;
while allowing
    i = i + 1;
    a[i] = i;
6.5.15 Conditional operator
...
4 The first operand is evaluated; there is a sequence point between its evaluation and the evaluation of the second or third operand (whichever is evaluated). The second operand is evaluated only if the first compares unequal to 0; the third operand is evaluated only if the first compares equal to 0; the result is the value of the second or third operand (whichever is evaluated), converted to the type described below.110)
110) A conditional expression does not yield an lvalue.
6.5.16 Assignment operators
...
3 An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment,111) but is not an lvalue. The type of an assignment expression is the type the left operand would have after lvalue conversion. The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.
111) The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type.

In the expression

a = (a < b ) ? a++ : b++

there is a sequence point between the evaluation of (a < b) and a++, but there is no sequence point between the evaluation of a on the LHS of the = operator and a++; thus, the behavior is undefined.

In the expression

a = (a++ < b++) ? a : b

there is a sequence point between (a++ < b++) and the a on the RHS of the ? operator, but there's no sequence point between the a on the LHS of the = operator and (a++ < b++); again, the behavior is undefined.

Upvotes: 0

Manos Nikolaidis
Manos Nikolaidis

Reputation: 22244

Both cases involve undefined behaviour of some sort because you are incrementing a, returning a and assigning to a on the left side within 2 sequence points. 3 would be required for a clearly defined result.

In this case : a = (a < b) ? a++ : b++;

  1. if a is smaller than b
  2. a is returned (value = 5) as the result of the ternary operator
  3. a is incremented (value = 6).
  4. the result of the ternary operator (5) is assigned to the left hand side variable a (over-writing 6)

The order of steps 3 and 4 is not defined. It is equivalent to a = a++;

In this case : a = (a++ < b++) ? a : b;

  1. If a is smaller that b
  2. a and b are incremented (regardless which is smaller)
  3. a is returned as the result of the ternary operator
  4. it is assigned to the left hand side variable a

The order of steps 2 and 3 is not clearly defined.

It's important to keep track of sequence points in such cases. Relevant rules :

  • The 1st expression of ternary operator on the left of ? is sequenced before the 2nd or 3rd expressions. And either of them is sequenced before assignment.
  • The comparison is sequenced before the ?
  • In expressions like a++ the value is returned before incrementing

Undefined behaviour:

  • In expressions like a = a++; there is no sequence point between (post)incrementing a and assigning to a on the left side. Both happen after the original value of a is returned
  • In expressions like a++ ? a : b there is no sequence point between (post)incrementing a and returning a from the ternary operator. Both happen after the ?

Upvotes: 2

Jens Gustedt
Jens Gustedt

Reputation: 78973

The one line that gives you the unexpected result has an error: you are not allow to modify an object (here a) twice in the same expression without separating them by a "sequence point".

The ? in the other one is a sequence point, so that one works.

If you do so (modify twice without sequence point) the behavior of your program becomes undefined. That is you can't make any reasonable assumption of what the program should produce and thus you see some unexpected results that even will vary according to the compiler and its version.

Upvotes: 1

Related Questions