> How do enums map to hardware? How do structs?
As integers? Sequentially in memory? And that's about as much as I care.
> Would adding generics mean that C maps less to hardware? What would that even mean?
It means that you have control. That's what you need for good and (equally important) consistent performance and low memory footprint. You have pretty good basic low-level abstractions (integers, pointers, structs, functions) that are very convenient to work with (much more convenient than your typical assembler language), and at the same time as low-level as you care to go most of the time. And even then, toolchains have good support to go even lower when you need to.
> [citation needed]
My personal experience with simple languages like C, Python, and complex typed ones like C++, Haskell. (There are also boilerplate ones like Java (not interested, thanks), or ones that swallow errors too easily to be productive, like sh, Javascript).
Also, look at other projects. Look how successful game programmers use C++ (In my filter bubble I watched people like Jonathan Blow, Mike Acton, Casey Muratori on Youtube, and have been following Sean Barrett or looked at imgui or quake3). What they do is pretty much C. I have also been following the Haskell community quite a bit and watched C++ experiments like boost, and they simply have a different focus. They don't get things done (in general), their builds are time consuming and brittle, their code is hard to understand, etc...
> And if C is all about talking directly to the hardware, how come the language has no first class support for SIMD, for preload, for the various CPU flags?
It's not assembler... It's "portable assembler", as some people like to say. And if you need support for SIMD etc, just take second class support or drop to inline assembler. No point in arguing here.
> And to get back to our point, how does NULL map to hardware? A CPU has no issue addressing at 0, it's nothing special. An assembler doesn't treat address 0 differently from any other, unlike C explicitly does.
There are always these language lawyer type unfortunate exceptions and complexities that can be explained by a little bit of history. Personally I'm mostly on x86 and I sometimes assume it's binary 0, but actually I don't really care that much.
> A CPU has no issue addressing at 0, it's nothing special. An assembler doesn't treat address 0 differently from any other, unlike C explicitly does.
Making my point. It's just data. I think NULL is actually just ((void * )0), but it's the representation of 0 that is special on some architectures. That the representation might not be all binary 0s on some architectures is probably pretty complicated to explain. As far as I'm concerned it's a language lawyer thing and I don't care.
C might technically not be simple, but your use of it can (and maybe should) be simple.
> My point is that in this case the rem pointer is an algebraic data type.
What is is? If you insist on looking at it like that, why don't you use Haskell? Though, you will have to take a performance hit and might have a harder time developping new features, because modularity is very bad due to complex typed interfaces.
By the way, I know how the nanosleep interface works. I don't have any problem understanding and remembering that and using it correctly (and it's not like I have used it more than 3 times in my life). I don't think I would make an error, but I wouldn't care if the null option would go away completely, either.
It's much harder to correctly use struct timeval / timespec than calling nanosleep. The null thing is totally a theoretic non-issue.