A simple example is function argument evaluation order. If you have:
foo(bar(), baz())
A compiler is free to call these functions in either order. That means if baz relies on state mutated by bar, the program may behave differently if the compiler chooses to reorder evaluation.
lock_two_widgets(widget *a, widget *b) {
if (a < b) {
lock(&a->lock);
lock(&b->lock);
} else {
lock(&b->lock);
lock(&a->lock);
}
}Edit: Your code has undefined behavior, unless the two pointers point to the same object, which is unlikely in a realistic example.
It is defined behavior to read the bytes of any object using unsigned char.
If you wrote `foo(bar(), baz())` and `baz()` relies on state mutated by `bar()`, your code is bad, and you should feel bad, because experiencing those bad feelings is the way you learn to not write bad code. This code was wrong before the compiler reordered the calls, it just failed silently for a while. The compiler isn't responsible for fixing your bugs, you are.
People need to stop expecting other people to fix their problems.
foo(baz(bar()))This is, of course, a rule of thumb, not a hard law. Some exceptions:
1. I think it's okay (and in fact, idiomatic in C) to mutate state and return some sort of information about what occurred (i.e. a success flag, a number of characters written, etc.).
2. Isolated mutations such as logging sometimes make sense in an otherwise pure function.
return foo().baz().bar();
With flags you start with success/fail, and end up with HRESULT.That's it. Simple education.
In the context of this post I think that's a good thing because not everyone will understand the topic.
You, however, seen to have read some sort of agenda in the question, which I find a little baffling...
Certain things are unspecified. It can call in any order for example.
Other things are undefined. If you do them your program is no longer valid at all, and can crash or corrupt.
Theoretically "stop doing that" works... but history has shown that it really doesn't work in practice, in C, in programming more broadly, and, really, in any human endeavour ("planes don't need safety procedures, just stop making mistakes").
I have yet to see a thorough (source-to-compiler-intent-to-assembly) comparative description of undefined, unspecified and implementation-defined behaviors, though (not just a somewhat insightful blog, or techno gospel, which the C and C++ standards are).
But yes, authoring a book titled "Well-defined C (and C++)" one day would be awesome.
Thanks for the link.