Weird compiler behavior

Recently I have stumbled across a piece of code, that puzzles me, because different compilers compile it in a different way:

#include <iostream>
using namespace std;
int main() {
int a = 3;
int& ref = a;
int b = ref;

ref = a++ - b;
cout << a << ref << b;

return 0;
}

Microsoft VC x86 compiler version 2017, g++ and clang compile it so that it produces 003, and VC x64 2017, and 2019 versions of VC compile it so that it produces 113.
The difference when the compiled code is disassembled is that the former perform the increment of a before the assignment, and the latter do it after the assignment.
My question is: what is the right way to do it?


My question is: what is the right way to do it?

Well it looks like you're running into undefined behavior. Remember that a reference is an alias, so a++ - b would be the same as a++ - a, which is undefined behavior.

The problem is one of evaluation order, not operator precedence: it cannot be corrected by adding parentheses.

The problem is easier to see once some extraneous variables are removed:
1
2
3
4
5
6
int main()
{
  int a = 3;
  a = a++ - 3;
  std::cout << a;
}


Since C++17: the output is 0. The value computation and side-effects of the left operand of the assignment are sequenced-before the side-effects of the assignment expression.

(e.g. a = a++ leaves a unchanged: the compiler is required to carry out the side-effects of a++ before assigning the value of a++ to a).

Before C++17: the behavior is undefined. The value computation but not the side-effects of the left operand of the assignment are sequenced-before the side-effects of the assignment expression. Therefore two modifications to a are unsequenced, resulting in undefined behavior.
https://en.cppreference.com/w/cpp/language/eval_order

(e.g., a = a++ has undefined behavior because the compiler is not required to carry out the side effects of a++ before assigning the value of a++ to a. The assignment could happen first, in which case a would be incremented. Or the increment could happen first, in which case a would be left unchanged. Or, in theory, evaluation of the side-effects could be interleaved, resulting in unpredictable behavior.)
Last edited on
Topic archived. No new replies allowed.