> C is essentially portable assembly
Not really, assembly shows you what the machine instructions actually are. In C you have loops, functions structs. All things that make no sense in assembly.
Loops (conditional JMPS - JE/JNE/JZ/JNZ/JB/JNB.. and a dozen others) and functions (CALL, RET) exist in assembly. Goto is there too (all JMPs). C makes assembly sense.
Both points are specious. C disassembly is usually not an orthogonal translation of the structures in the code, usually due to optimisation.
> In C you have loops, functions structs. All things that make no sense in assembly.
One can reasonably infer that a loop will roughly translate to some type of conditional jump instruction. Function structs are just pointers and call instructions. The former point was that there is little runtime getting in the way of how the constructs could be expressed, and a long time ago it may have been the truth, but not for modern compilers.