0

While working on a C++ project with Visual C++ Express 2010 I've found an interesting issue that I'd like to understand. The problem is that the result of my program is different if I compile in Debug or Release modes. I made a small program to reproduce it:

#include <stdio.h>


int firstarg(int i)
{
    printf("First argument called with i = %d\n", i);

    return i;
}

int secondarg(int i)
{
    printf("Second argument called with i = %d\n", i);

    return i;
}

void function(int i, int j)
{
    printf("Function called with %d, %d\n", i,j);
}

int main(int argc, char* argv[])
{

    // Line with the problem!
    for (int i = 0; i < 5; ) function(firstarg(i), secondarg(i++)); 

    return 0;
}

// Result on RELEASE:
Second argument called with i = 0
First argument called with i = 0
Function called with 0, 0
Second argument called with i = 1
First argument called with i = 1
Function called with 1, 1
Second argument called with i = 2
First argument called with i = 2
Function called with 2, 2
Second argument called with i = 3
First argument called with i = 3
Function called with 3, 3
Second argument called with i = 4
First argument called with i = 4
Function called with 4, 4

// Result on DEBUG
Second argument called with i = 0
First argument called with i = 1
Function called with 1, 0
Second argument called with i = 1
First argument called with i = 2
Function called with 2, 1
Second argument called with i = 2
First argument called with i = 3
Function called with 3, 2
Second argument called with i = 3
First argument called with i = 4
Function called with 4, 3
Second argument called with i = 4
First argument called with i = 5
Function called with 5, 4

As you see, in both cases the second argument is evaluated before the first one (that one I expected, if arguments are processed in some kind of LIFO stack); but in release the increment of the variable i is "optimized away" and delayed until the next iteration of the loop. That was unexpected, and I'd really would like to understand what's going on.

Of course, I can easily "fix" my code by changing the loop to

    for (int i = 0; i < 5; ++i) function(firstarg(i+1), secondarg(i)); 

which will give always the same result regardless of compilation parameters. But, still, what I would really like to understand the reasons behind this optimization of increments.

PS. By the way, I could not reproduce this problem with gcc under linux (Debug with -O0 flag, Release with -O3).

Glue
  • 63
  • 1
  • 4

3 Answers3

3

You are misunderstanding the results. The increment is not "optimized away" or delayed until the next iteration of the loop. You just have no way to see what the value of i is before the next iteration. Try this:

for (int i = 0; i < 5; )
{
   function(firstarg(i), secondarg(i++)); 
   printf("At end of iteration, i = %d\n");
}

And you'll see that it's not delayed at all.

Your code is UB because you have an access of a variable and a modification of that same variable without an intervening sequence point. While you could get really crazy results, in fact you get both of the "expected" results, depending on your optimizations. The order in which function parameters are evaluated is unspecified.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
2

Your program modifies and reads the variable i twice without an intervening sequence point (in the function call expression for function), which is simply undefined behaviour.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

I think you have a problem of sequence points leading to undefined behaviour:

The solution in any case is to not write this kind of code.

Community
  • 1
  • 1
BlueTrin
  • 9,610
  • 12
  • 49
  • 78