I agree that it is an oxymoron. And while many C (and C++) programmers
understand that, some do not - they really do think that C is, was,
should be, or should have been "portable assembly".
>>
>> 1. Assembly is defined in terms of the hardware, C is defined in terms
>> of a high-level abstract machine (with some flexibility to fit hardware
>> better).
>>
> But C has some looseness in that you can inspect pointers, which in practice
> hold the same bits that the processor uses to address memory.
Yes, but much of what you can do with them is implementation dependent
(and therefore not very portable), or undefined behaviour (and /might/
do something you find useful, but your should consider your code tied to
exactly the compiler, target, version and options that you have used in
testing).
>>
>> 2. Assembly is a list of commands, and the generated code follows them
>> closely (some assemblies have minor modifications during the process).
>> C is also an imperative language, but does not require the results to
>> follow the source code as long as the defined end result is the same.
>>
> It doesn't require it. But usually it's possible to write a conforming C compiler
> in which each C construct maps simply onto another machine code construct.
If you write such a compiler, then you could possible argue that the
/compiler/ could be used as a kind of high-level assembler. But the
existence of such a compiler does not affect the C language - as long as
you can make a conforming C compiler which does /not/ do such simple
translation, C is not a "portable assembler".
> The main difference is that a C compiler can optimise poorly written or human
> rather than computer meaningful code to produce more efficient machine code.
> If an assembler does this, you've got to ask whether it is really still an assembler.
>>
>> 3. Assembly synchronises the "abstract machine" of the language, and the
>> hardware of the processor, at pretty much every line of code. In C,
>> they only need to be synchronised at points of "observable behaviour".
>>
> That's another way of saying the same thing.
I don't think so, but they are certainly related.
> However you can't solve the halting
> problem.
What does that have to do with anything?
> In reality there are limits to how far you can translate one sequence of
> imperative instructions into another, equivalent sequence of imperative instructions,
> without points of synchronisation in which the logical state is the same.
No, there are no such limits. Any one given compiler may have limits to
its optimisations, and it may get harder and harder to write new
optimisations which then give smaller and smaller increases in
efficiency. But there is no hard limit - real, practical, or
theoretical. You can't make a compiler that always produces the
optimally efficient results for any input (the proof of that claim is
left as an exercise for the reader), but there is not a specific limit
point.