4
#include<stdio.h>
int main()
{
    int a=4;
    int b=4;
    int c= a++ < ++b? 1 : 0;
    
    printf ("%d",c);
}

It is known that there is a sequence point at ?, which means that both the prefix and postfix operations have to be completed by that point. Also it is known(?) that b is incremented before the comparison. However, is a incremented before or after the comparison?

If it is incremented before the < test, then the Boolean evaluates to false and c is set to 0, else to true with c being set to 1. In my compiler, it evaluates to true, which means a++ is performed after the comparison operation with c being set to 1.

Is this behavior part of the specification though?

I modified it to

#include<stdio.h>
int main()
{
    int a=4;
    int b=4;
    int d=2;
    int c= a++ + d < ++b + d? 1 : 0;
    
    printf ("%d",c);
}

and it still evaluates to 1. The postfix has to complete before the ?, but does that really ensure that it happens after the comparison < ?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
user2277550
  • 553
  • 7
  • 22
  • 2
    `a` is incremented after the comparison. Post-increment, so the un-incremented value is used. – Weather Vane Jan 11 '23 at 15:45
  • 3
    `int c= a++ < ++b? 1 : 0;` could be replaced directly with `int c= a++ < ++b;`, although I'd probably use `int c= (a++ < ++b);` to make the intent to assign the result of the boolean comparison to `c` clear. – Andrew Henle Jan 11 '23 at 15:54
  • It is irrelevant to the result of the comparison whether the stored value of `a` is modified before or after the comparison is evaluated. What matters is the value of the *expression* `a++`, which is the value of `a` before the increment, regardless of when the stored value of `a` is modified relative to other program behaviors. – John Bollinger Jan 11 '23 at 16:45

3 Answers3

9

a++ returns the value of a before the increment. ++b returns the value of b after the increment. Thus this evaluates to 1.

As neither a nor b are used more than once in the expression, no undefined behavior exists.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Chris
  • 26,361
  • 5
  • 21
  • 42
  • Hi, can you point me to some resources on the formal rules regarding the postfix operator? – user2277550 Jan 11 '23 at 16:03
  • 1
    @user2277550 related: [sequence points in c](https://stackoverflow.com/questions/3575350/sequence-points-in-c). The post-increment occurs at an unspecified moment somewhere between the value being read, and the next sequence point. – Weather Vane Jan 11 '23 at 16:05
  • @WeatherVane But that sequence point is '?', right? – user2277550 Jan 11 '23 at 16:18
  • 1
    This Wikipedia article about [sequence points](https://en.wikipedia.org/wiki/Sequence_point) says *2. Between the evaluation of the first operand of the ternary conditional operator and its second or third operand. For example, in the expression `a = (*p++) ? (*p++) : 0` there is a sequence point after the first `*p++`, meaning it has already been incremented by the time the second instance is executed.* But, it still does not happen *before* your `c` was read: that would be pre-increment. – Weather Vane Jan 11 '23 at 16:24
  • 1
    @user2277550 Do worry about the sequence point in terms of which updated values get stored into `a` and `b`, and when. But the sequence point has nothing to do with the values seen by the `<` operator. As far as the `<` operator is concerned, the expression might as well be `c = a + d < (b+1) + d? 1 : 0`. See also [my answer](https://stackoverflow.com/questions/75085596/will-this-expression-evaluate-to-true-or-false-1-or-0-in-c/75086071#75086071). – Steve Summit Jan 11 '23 at 16:30
6

Also it is known(?) that b is incremented before the comparison. However, is a incremented before or after the comparison?

This is a subtle point, but it's important to understand what's really going on here.

Both the subexpressions a++ and ++b do two things. They compute a new value to be used in the surrounding expression, and they update the stored value of the variable they're operating on.

So a++ does this:

  1. it yields the old value of a (4) out to the surrounding expression
  2. it stores a new value (5) into a.

And ++b does this:

  1. it yields the new value of b (4+1 or 5) out to the surrounding expression
  2. it stores a new value (5) into b.

Notice that in both cases it's thing 1 that the < operator cares about. And, in both cases, thing 1 is an absolute definition, it doesn't depend on timing.

Or, in other words, asking "Is a/b incremented before or after the comparison?" is not really the right question. The values a and b+1 participate in the comparison, and that's it.

Where the timing comes in is things 2. We don't know, precisely, when the new value gets stored back into a. Nor do we know precisely when the new value gets stored back into b. All we know is that those stores will happen sometime before the next sequence point (which, as you correctly note, in this case is the ? part of the ternary operator).

But nothing depends on those timings, so there's no undefined behavior here.

Undefined behavior comes in when either

  1. the variable that's modified (a or b) also has its value independently used elsewhere in the expression, meaning that we don't know whether that use uses the old or the new value
  2. the same variable is modified twice, meaning that we don't know which of the two modifications "wins"

But, again, neither of those problems occurs here, so the expression is well-defined.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
0

From the C Standard (6.5.2.4 Postfix increment and decrement operators)

2 The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it).

So in this declaration

int c= a++ < ++b? 1 : 0;

the value of the sub-expression a++ used in the initializer is the value of the operand a before its increment.

On the other hand (The C Standard (6.5.3.1 Prefix increment and decrement operators) )

2 The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation.

So the value of the sub-expression ++b is the value after incrementing b.

Hence you have in fact

int c = 4 < 5 ? 1 : 0;

As for the sequence point then to demonstrate it you could write for example

int c = a++ < b++ ? a : b;

In this case the variable c will have the value of the variable b after applying to it the side effect of incrementing that is to 5.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335