pornel 5 days ago

Less controversially, when you write C, you write for a virtual machine described by the C spec, not your actual hardware.

Your C optimizer is emulating that VM when performing symbolic execution, and the compiler backend is cross-compiling from it. It's an abstract hardware that doesn't have signed overflow, has a hidden extra bit for every byte of memory that says whether it's initialized or not, etc.

Assembly-level languages let you write your own calling conventions, arrange the stack how you want, and don't make padding bytes in structs cursed.

2
bmandale 5 days ago

These are all such nonsensical misinterpretations of what people mean when they say C is "low level". You absolutely don't write C for the C abstract machine, because the C spec says nothing about performance, whereas performance is one of the primary reasons people write C.

The existence of undefined behaviour isn't proof that there is a C "virtual machine" that code is being run on. Undefined behaviour is a relaxation of requirements on the compiler. The C abstract machine doesn't not have signed overflow, rather it allows the compiler to do what it likes when signed overflow is encountered. This is originally a concession to portability, since the common saying is not that C is close to assembly, but rather that it is "portable" assembler. It is kept around because it benefits performance, which is again one of the primary reasons people write C.

pornel 5 days ago

I'm not trying to prove a novel concept, just explain how the C spec thinks about C:

> The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant.

This belief that C targets the hardware directly makes C devs frustrated that UB seems like an intentional trap added by compilers that refuse to "just" do what the target CPU does.

The reality is that front-end/back-end split in compilers gave us the machine from the C spec as its own optimization target with its own semantics.

Before C got formalised in this form, it wasn't very portable beyond PDP. C was too opinionated and bloated for 8-bit computers. It wouldn't assume 8-bit bytes (because PDP-11 didn't have them), but it did assume linear memory (even though most 16-bit CPUs didn't have it). All those "checking wetness of water... wet" checks in ./configure used to have a purpose!

Originally C didn't count as an assembly any more than asm.js does today. C was too abstract to let programmers choose addressing modes and use flags back when these mattered (e.g. you could mark a variable as `register`, but not specifically as an A register on 68K). C was too high level for tricks like self-modifying code (pretty standard practice where performance mattered until I-cache and OoO killed it).

C is now a portable assembly more because CPUs that didn't fit C's model have died out (VLIW) or remained non-standard specialized targets (SIMT).

pjmlp 5 days ago

C performance exists thanks to UB, and the value optimising compilers extract out of it, during the 8 and 16 bit home computers days any average Assembly developer could write better code than C compiler were able to spit out.

codr7 5 days ago

And also because it doesn't get in your way of doing exactly what you want to do.

OCASMv2 5 days ago

If that was true then the optimizers wouldn't need to exist in the first place.

codr7 5 days ago

Compared to the alternatives.

It gets very frustrating to communicate at this level.

pjmlp 5 days ago

The alternatives outside Bell Labs were just as capable.

OCASMv2 5 days ago

I don't think compilers allowing trash through is a good thing.

codr7 4 days ago

That's an opinion, another one would be that the flexibility allowed by undefined behavior is one of C's strengths at the same time. Strength/weakness are often two sides of the same coin. Which is why these discussions get a bit circular.

greenavocado 4 days ago

Have you ever seen the error steamroller? https://github.com/mattdiamond/fuckitjs

dwattttt 4 days ago

ON ERROR RESUME NEXT rears its ugly head again

aninteger 5 days ago

> Less controversially, when you write C, you write for a virtual machine described by the C spec, not your actual hardware.

Isn't this true for most higher level languages as well? C++ for instance builds on top of C and many languages call into and out of C based libraries. Go might be slightly different as it is interacting with slightly less C code (especially if you avoid CGO).