user2277550
user2277550

Reputation: 619

Will this expression evaluate to true or false (1 or 0) in C?

#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 < ?

Upvotes: 3

Views: 250

Answers (3)

Chris
Chris

Reputation: 36620

The expression a++ returns the value of a before the increment operation, while ++b returns the value of b after the increment operation. Thus this reduces to 4 + 2 < 5 + 2 which reduces to 6 < 7 which is true, so the expression a++ + d < ++b + d ? 1 : 0 evaluates to 1.

As neither a nor b are used more than once in the expression, no undefined behavior exists. Were they, you'd want to review Why are these constructs using pre and post-increment undefined behavior?

Upvotes: 9

Steve Summit
Steve Summit

Reputation: 48023

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 in the question is well-defined.

What would not be defined would be if you said something like

c = a++ < ++a ? 1 : 0;           /* WRONG */

This expression is rampantly, classically undefined, because now we have two side effects affecting the same object, a. Now, when we try to say that "a++ yields the old value of a out to the surrounding expression", we have a major, significant, unresolvable ambiguity: does "the old value of a" mean the value a had before this expression ever began, or could it mean the value of a as modified by some other part of the the expression we're in the middle of?

And there is no, repeat no, way to answer this question. It's tempting to read an expression left to right, or to look at the defined associativity of various operators, but there's no rule in C to say that those factors actually influence the order that side effects happen in. So the expression a++ < ++a is undefined, even though the similar-looking a++ < ++b is well-defined.

Upvotes: 8

Vlad from Moscow
Vlad from Moscow

Reputation: 311088

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.

Upvotes: 0

Related Questions