2

I've read from Order of evaluation, and I don't understand it well. Does the order mean the execution order in run time or just the logic order in the source code?

Let's see a code snippet as below:

void f()
{
   int a = 10; // A
   int b = 20; // B
   //...
}

Does it mean that expression A is sequenced before expression B?

And is the c++ compiler allowed to reorder the code as below?

void f()
{
   int b = 20; // B
   int a = 10; // A
    //...
}

If a compiler does reorder the code as above, then should we say that expression B is sequenced before A?

ricky
  • 1,768
  • 3
  • 15
  • 40
  • 2
    Sequencing is about the evaluation order at *run-time*. And the compiler can reorder anything as long as it doesn't break the sequencing rules. The rules are also for *expressions* not statements. As for your example, it's irrelevant to the sequencing rules since it's two *statements*, and the compiler can reorder it as it pleases since it's two *independent* statements. If you had e.g. `int b = a;` then it couldn't be reordered. – Some programmer dude Nov 09 '18 at 10:09
  • @Someprogrammerdude what about if i had int a = x + 1; int b=y+1;? – ricky Nov 09 '18 at 10:17
  • That still two independent statements that has no dependencies on each other. And the compiler could reorder those initializations in any way it pleases. – Some programmer dude Nov 09 '18 at 10:18
  • Also please read [Undefined behavior and sequence points](https://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points). It could help you understand these things better. – Some programmer dude Nov 09 '18 at 10:19
  • 1
    And lots of modern CPUs are out of order, so they can also reorganize instructions on the fly, as long as there is no dependency between them. – Matthieu Brucher Nov 09 '18 at 10:20
  • Related post [What are the evaluation order guarantees introduced by C++17?](https://stackoverflow.com/q/38501587/1708801) and some examples of where it can go wrong [Order of evaluation of assignment statement in C++](https://stackoverflow.com/q/33598938/1708801) and [this](https://stackoverflow.com/q/27158812/1708801 – Shafik Yaghmour Nov 09 '18 at 14:19

1 Answers1

5

As a general rule, the compiler is allowed to do anything at all as long as the outcome is the same as if it had compiled your code exactly as written.

In fact, your typical C/C++ compiler, with any reasonable optimization flags enabled, given a function like:

void f (void) {
  int a = 20;
  int b = 10;
}

will simply compile it as:

f:
  ret

In other words, it will treat it as an empty function. The reason is that the function has no effects whatsoever; those variables are assigned to, but their values are never used (in technical terms, they are dead stores), and thus the compiler can ignore them.

Now, let's look at a more practical example:

void foo (int num, int * num2, int * num3) {
  *num2 = num * 2;
  *num3 = num * 3;
}

Can the compiler reorder those statements? The answer is a firm no. The reason is that num2 and num3 may point to the same address (in other words, you may call the function like foo(3, &bar, &bar)), and thus the order of the writes matters. On the other hand, in C only (but not C++), we could write it like so:

void foo (int num, int * restrict num2, int * restrict num3) {
  *num2 = num * 2;
  *num3 = num * 3;
}

In that case, the restrict keyword tells the compiler that the pointers must point to different addresses, and thus reordering the statements is allowed, as the results are the same regardless of the order in which they are executed.

aaaaaa123456789
  • 4,586
  • 18
  • 30
  • Thanks for explanation! So compiler reorder have nothing to do with the evaluation order? – ricky Nov 09 '18 at 10:30
  • Why would the order in `foo` matter? You are overwriting variables with independent values – Fureeish Nov 09 '18 at 10:32
  • 1
    @Fureeish Because `num2` and `num3` could point to the same place (they are pointers), as I showed in the example of calling it like `foo(3, &bar, &bar)` — `bar` would first become 6 and then 9, but it has to happen in that order, as the final result must be 9. In the last example (which is only valid in C, as C++ doesn't have `restrict`), I'm explicitly saying that the pointers will point to different places (since that's what `restrict` means), which makes it work like you say — and thus it _can_ be optimized in that case. – aaaaaa123456789 Nov 09 '18 at 10:34
  • Ah, that makes sense. I got somehow lost there :> – Fureeish Nov 09 '18 at 10:35
  • @ricky I somehow never saw your comment, sorry! Evaluation order is the ideal order in which expressions are evaluated; the compiler must behave _as if_ they were evaluated in that order. *Re*ordering, as given by the name, is the compiler's ability to evaluate expressions in any order it likes (typically for performance reasons), making the necessary adjustments, as long as the results and the final effects are identical. – aaaaaa123456789 Nov 09 '18 at 13:15
  • Note, however, that `restrict` is not standard C++. It's in C99, and apparently some compilers support it in C++. – Pete Becker Nov 09 '18 at 14:26