Many compilers have magic incantations for explicitly suppressing the inlining of certain functions, like
__declspec(noinline). An alternative is introducing something that the optimizer is not allowed to 'see through', like a (volatile) function pointer or an external DLL function. A vararg function can sometimes be used with similar effect (i.e. pretend to use the result of some computation in order to force the compiler to actually perform it).
The convention underlying all this is the 'as if' rule in the C/C++ standards. The compiler must ensure that the observable behaviour of the resulting binary follows the defined semantics; how these results are arrived at is completely up to the compiler.
In connection with a good optimising compiler this makes the source code of a program a logical specification (or contract) of what the programmer expects to happen, and the physical realisation is fully up to the compiler. This is a good thing, and long overdue.
Contrast this to glorified macro assemblers like Turbo Pascal and older Delphis, where you know exactly which machine code fragment/template will get emitted for which source code construct (barring a small handful of tricks from the Dragon Book, like dead store elimination).
Here are a few relevant verses from Scripture (ISO/IEC 14882:2003 alias C++03):
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.
A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible execution sequences of the corresponding instance of the abstract machine with the same program and the same input. However, if any such execution sequence contains an undefined
operation, this International Standard places no requirement on the implementation executing that program with that input (not even with regard to operations preceding the first undefined operation).
(IOW, if you invoke undefined behaviour then all bets are off and the compiler may do whatever it pleases - including, but not limited to, crashing your computer or selling your wife on Ebay. Modern compilers tend to rely heavily on this clause.)
The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.
The least requirements on a conforming implementation are:
— At sequence points, volatile objects are stable in the sense that previous evaluations are complete and subsequent evaluations have not yet occurred.
— At program termination, all data written into files shall be identical to one of the possible results that execution of the program according to the abstract semantics would have produced.
— The input and output dynamics of interactive devices shall take place in such a fashion that prompting messages actually appear prior to a program waiting for input. What constitutes an interactive device is