2

It came to my attention the following fact: order of function evaluation, for example in a sum, is unspecified in the standard, and can therefore be performed in any order.

This raises the question: is it compiler dependent, optimization dependent, or potentially even execution dependent (I doubt it, it may involve reshuffling of the code, but in today's multicore environments, I guess some compilers may see a chance for optimization in this lack of specification, by implicitly performing the two calls in parallel) ?

Edit: I want to clarify. The fact that order is unspecified in the standard, does not imply it's unspecified for a particular compiler (which may choose to make it specified in the documentation, I assume). Unspecified behavior may make you non-portable, but the compiler may behave consistently according to a given rule. I am interested in knowing, purely for academic curiosity, if this specification is actually made by compilers (e.g. in the manual) and if yes, if this choice is consistent or may be altered by compiler options or other factors. Example, take gcc. How does it behave? is it consistent ?

Community
  • 1
  • 1
Stefano Borini
  • 138,652
  • 96
  • 297
  • 431

3 Answers3

12

It's unspecified - what more can we say? As you should never write code that depends on the order (because the compiler certainly could change it), the question is of academic interest only. If you are really interested in what your specific compiler gets up to, examine the emitted machine code in the scenarios that interest you.

  • yes, I'm only curious about the internals. I don't plan to exploit the local compiler behavior. – Stefano Borini May 29 '11 at 19:23
  • I agree that is unspecified, but in practice a given compiler will behave in either a consistent, predictable way, or not, depending on the compiler. I was hoping for an answer on the like: this compiler always calls in this order, but this other compiler exploits parallelism and may call according to how it wakes up in the morning, or for this compiler the order is this but if you do -O3 it may shuffle it. – Stefano Borini May 29 '11 at 19:26
  • @Stefano Well, I doubt that many people (apart from the compiler implementers) are in a position to say those things. I've certainly never taken an interest in the implemented evaluation order for the compilers I use, and I've never seen it documented in any compiler's documentation. –  May 29 '11 at 19:31
  • You never know. The SO distributed brain may know things we deemed impossible to know. – Stefano Borini May 29 '11 at 19:37
4

It can't interleave function calls (in cases where you can tell the difference) because there are sequence points at calling and returning from a function.

Other than that, the compiler can evaluate parts of an expression in any order it sees fit. The standard explicitly states that it doesn't prescribe an order, except what follows from the operators used in the expression.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • +1 for pointing out that interleaving the functions/running them in parallel is not a legal optimization (unless the functions can be proven to be pure or at least not to have side effects that could be visible to one another). – R.. GitHub STOP HELPING ICE May 29 '11 at 23:58
3

Answering your second question:

Edit: I want to clarify. The fact that order is unspecified in the standard, does not imply it's unspecified for a particular compiler (which may choose to make it specified in the documentation, I assume). Unspecified behavior may make you non-portable, but the compiler may behave consistently according to a given rule. I am interested in knowing, purely for academic curiosity, if this specification is actually made by compilers (e.g. in the manual) and if yes, if this choice is consistent or may be altered by compiler options or other factors. Example, take gcc. How does it behave? is it consistent ?

I have never seen this documented for any compiler. Doing so would limit the options for future versions of the compiler, without giving much value to the users of the current version. If you have a particular need for a specific evaluation order, you can always get that by adding a few extra semicolons!

Code isn't optimized one statement at a time, but over the whole function or even larger parts if code is inlined. How you evaluate a particular statement depends on the surrounding code. Perhaps one value has already been computed and used in a preceding statement? It may already be present in a CPU register and can be reused.

Or perhaps one of the subexpressions can be reused later, if it is computed last? That an affect the evaluation order, as can the calling convention used for a specific call.

It is anyway generally a bad idea to code against the specifics of a particular compiler. You never know when you will have to port to another one.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203