> I guess the next question is why is expression evaluation in a case like this undefined?
Because it's a lot easier to say that, than write a bunch of rules to cover the general case - 'x' variables being modified 'y' times in the same expression. Not only do you have to write the rules, but compiler writers have to implement them and test them extensively (and people would endlessly ask questions on message boards as to why the rules are so damn complicated). Add in the variety of machine architectures and optimisation levels and before you know it, you have a big mess.
It's far simpler to constrain the rules to being one variable modified at most once.
How would you tackle something like this?
i = ++i - i++;
It's not just the ++/-- operations which have side effects, consider something like a function call
a = a + foo(&a);
It might be obvious in this case, but with an aliased pointer, you're sunk.