Articles like this and the three-part series about undefined behavior on the LLVM blog [0] ought to be required reading for anyone who still has the impression that C is "portable assembler".
The legitimate use of the notion that "C is portable assembler" is as a reflection of the purposes to which it is put. Unquestionably there can be an arbitrarily large gulf between the C code and the micro-semantics of the generated assembly. Though it doesn't stop there - there's always some space even between the machine code and what actually happens - arguably larger these days, with out-of-order execution and similar optimizations.
Articles like this and the three-part series about undefined behavior on the LLVM blog [0] ought to be required reading for anyone who still has the impression that C is "portable assembler".
[0] http://blog.llvm.org/2011/05/what-every-c-programmer-should-...