-3

Are postfix increment/decrement operators evaluated after the expression is evaluated or after the entire statement is evaluated ?

#include<stdio.h>

void main()
{
  int a=0;
  int b=0;

  printf("%d %d",a||b,b++);  // Output is 1 0

}

My compiler evaluates the printf arguments from right to left. The answer of expression a||b is 1, it means that b has incremented before a||b has been evaluated(i.e b is incremented immediately after evaluating the expression b++)

I read here Incrementing in C++ - When to use x++ or ++x? that postfix increment/decrement are evaluated after the entire statement.

Which is correct?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Sagar P
  • 165
  • 6
  • 6
    Neither is correct. The behavior is undefined. See https://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior – interjay Oct 16 '17 at 11:44
  • So that answer which received so many upvotes incorrect? – Sagar P Oct 16 '17 at 11:45
  • @interjay, In general what is the behaviour if variables are not repeated in same statement ? Does postfix increment the value of the variable after evaluating the expression or after evaluating the entire statement? – Sagar P Oct 16 '17 at 11:48
  • 2
    @SagarP That answer is about the difference between post-increment and pre-increment. Post-increment returns the previous value and pre-increment returns the new value. The answer is misleading regarding the timing of the increment, as sellibitze's comment points out. – interjay Oct 16 '17 at 11:51
  • @interjay, So in post-increment after b++ statement, b is actually incremented first like in pre-increment but the value which is returned is old value right ? – Sagar P Oct 16 '17 at 11:57
  • The compiler can choose to perform the actual increment whenever it wants, as long as it's between the previous and next sequence point. If there are other accesses of the variable during that time, the behavior is undefined. The value returned must be the old one. – interjay Oct 16 '17 at 12:00
  • @Sagar P beforo you ask you should read another questions related to it. The ++ UB comes here 10 times a week. – 0___________ Oct 16 '17 at 12:06
  • The behaviour of anyone who writes code like that is also undefined, thiough getting fired immediate or getting an 'F-' grade are highly probable:( – Martin James Oct 16 '17 at 12:15
  • @SagarP - You might also want to note that this is duplicate #463 of that question. :-( – Bo Persson Oct 16 '17 at 12:29
  • @Bo Persson, So before sequence points, old value still remains but after reaching sequence point, the new incremented value is available which can be used by other variables right? – Sagar P Oct 16 '17 at 14:58
  • @SagarP - No, with `b++` we don't know exactly when the incremented value is stored back in `b`, except that it is no later than at the next sequence point. But it could happen earlier, maybe even immediately. And the rules say that you cannot read the value or perform an new update until the first update is completed. If you do, *anything* can happen. – Bo Persson Oct 16 '17 at 16:57
  • @Bo Persson, How can it happen immediately ? If have a statement if((i++==1)) with i value initially zero, then if i increments immediately then the condition is satisfied and it would be same as prefix increment. – Sagar P Oct 16 '17 at 18:35
  • @SagarP - Again, no. `i++` does **two** separate things, it increments `i` and it returns the original value. In any order. It *can* do `temp = i; i += 1; return temp;`, or just return `i` now and save the increment for later if that is more convenient. – Bo Persson Oct 16 '17 at 18:43
  • @Bo Persson. Got it, thanks . In preincrement there will be no temp variable right as we don't return old value ? It will be just i+=1 ; return i; . I appreciate your patience. – Sagar P Oct 16 '17 at 20:06
  • @BoPersson I don't think your statement regarding those 3 statements can be executed in any order is correct. What if "i" is incremented first and then temp stores this incremented value ? Then old value cannot be returned, instead it will be new incremented value. – Zephyr Oct 17 '17 at 13:38
  • 1
    @Zephyr - That's not what I tried to say. It's the **two** things, incrementing and returning the old value, that can be in any order. It's **never** incrementing and returning the new value (that's the other operator). – Bo Persson Oct 17 '17 at 13:43
  • @BoPersson Ahh, because of full stop before In, I read 2nd and 3rd statements together. – Zephyr Oct 17 '17 at 15:40

2 Answers2

6

The order of evaluations of function arguments is unspecified. All side effects related to the argument evaluations are applied before the control will be passed to the called function.

From the C Standard (6.5.2.2 Function calls)

10 There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call.

Here is a demonstrative program

#include <stdio.h>

struct 
{
    int x;
} a = { 0 };

void f( int x )
{
    printf( "x = %d\n", x );
    printf( "a.x = %d\n", a.x );
}

int main(void) 
{
    f( a.x++ );
}

Its output is

x = 0
a.x = 1

Due to the side effect in this call then one argument is dependent on a side effect of other argument and the evaluation of the side effect indeterminately sequenced relative the arguments

printf("%d %d",a||b,b++);  

the program has undefined behavior.

There are four operators in C when side effects are sequenced between operand evaluations. They are the logical AND operator (&&), logical OR operator (||)comma operator (,), and the conditional operator ( ?:).

For example

#include <stdio.h>

int main(void) 
{
    int x = 0;

    printf( "x = %d\n", x++ == 0 ? x : x - 1 );
}

The program output is

x = 1

The side effect of the evaluation of the expression x++ was sequenced before the evaluation the expression x after the ? sign.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • "aschepler"(below answer) says that "In f(x++);, the increment happens before calling f" . So in your example increment should happened before calling f right? – Sagar P Oct 16 '17 at 12:06
  • @SagarP The increment happens after the evaluation of the argument x++ (its value the value of the operand before incrementing) and before the control will be passed to the called function that is before the body of the function will be executed. – Vlad from Moscow Oct 16 '17 at 12:09
  • So before sequence points, old value still remains and is returned but after reaching sequence point, the new incremented value is available which can be used by other variables right? – Sagar P Oct 16 '17 at 14:59
  • @SagarP You are right provided that evaluation of expressions are sequenced. – Vlad from Moscow Oct 16 '17 at 15:36
0

The top answer of the question you linked to is inaccurate. The increment in x++ is only guaranteed to happen after determining the value of the expression, and sometimes before evaluating a containing expression, but there are no other guarantees on when it happens.

In particular, since side effects of arguments to the same function call are indeterminately sequenced, that program has undefined behavior.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • In general what is the behaviour if variables are not repeated in same statement ? Does postfix increment the value of the variable after evaluating the expression or after evaluating the entire statement? – Sagar P Oct 16 '17 at 11:49
  • @SagarP It depends. In `f(x++);`, the increment happens before calling `f`. In `g() + x++`, there's no guarantee on whether the increment happens before or after calling `g()` (but it can't happen during). – aschepler Oct 16 '17 at 11:55
  • In f(x--), does x really decrement before calling f? I still remember that I once called f(n--) and the code went into infinite recursion because the value of n was not decremented at all. – Sagar P Oct 16 '17 at 12:00
  • C11 6.5.2.2/10: "There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call." – aschepler Oct 16 '17 at 12:10
  • @SagarP - When you call `f(x--)` you get the old value passed to the function. It doesn't help that `x` is also decremented before the function is called. If you want the new value you just use `f(--x)`. – Bo Persson Oct 16 '17 at 12:21
  • @Bo Persson, Yeah, thanks ! – Sagar P Oct 16 '17 at 12:22