Just need a sanity check. The following would be unspecified, but not undefined, correct?
I am 99% sure it's just unspecified.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#include <iostream>
int x = 0;
int f() {
return x++;
}
int g() {
return x++;
}
void h(int y, int z) { std::cout << y << z << std::endl; }
int main()
{
h( f(), g() ); // order of evaluation here is unspecified, or completely undefined?
}
In other words, is the set of possible outputs of this program:
{ "01", "10"} or
{ "01", "10", "banana", pizza delivery, ... }
The program definitely works so it's not undefined. I compiled your code using the g++ compiler and it outputs "10". You're definitely a sane person as far as I know! It is just unspecified, for the compiler decides which parameters to evaluate first.
Speaking of which, I discovered that when one of my programs went out of bounds, it would always, without fail, cause someone to ring my doorbell around 30 minutes later, with a half-off pizza to deliver. But ever since that Meltdown fix, my program just crashes instead. Microsoft broke my workflow >:(
You are correct.
What is “unspecified” is the evaluation order of function arguments (this includes in mathematical operations): the value of arguments may be computed in any order, meaning that the functions f() and g() may be invoked in any order.
x = f() + g() * h(); // the functions may be called in any order!
If it makes a difference whether one function is called before the other, do it first:
auto g_result = g();
auto h_result = h();
auto f_result = f();
x = f_result + g_result * h_result;
The evaluations of the two sub-expressions f() and g() are indeterminately sequenced - they can't be interleaved.
(I'm pointing this out in case it was the i++ causing the confusion. Presumably if the evaluations were unsequenced, the program's behavior would be undefined rather than merely unspecified.)
One thing to keep clear in your head is the difference between precedence/associativity and order of evaluation. Precedence and associativity define the order of the operations. Order of evaluation defines the order in which the operands are evaluated.
Put another way, precedence tells you where the implicit parentheses go: is a - b - c evaluated as (a - b) - c or a - (b - c)? The language usually defines this.
Order of evaluation defines the order in which a, b, and c are evaluated (and when the intermediate result is evaluated too). This is almost always NOT specified.