> cryptic "undefined behaviors"
It's not really that cryptic (aside from like strict aliasing, but -fno-strict-aliasing). There's some UB that might be considered unnecessary/too strict, but it still makes sense in its own right, and, if understood, is quite powerful, and leads to a bunch of neat optimizations.
> the language doesn't feel easy to use/debug
If debugging at the assembly level, stepping by instructions, it's actually quite nice (despite what everyone says about it not mapping well to hardware, in my experience there's still a pretty clear & immediately obvious correspondence between each C thing and assembly subsection, and vice versa)
> CPP macros, a universally recognized bad idea
I don't know, they're quite neat for things I have to do. Sure, a turing-complete compile-time language would be nice (I'm not saying that sarcastically, I even use a DSL for writing SIMD that is exactly that!), but it'd add a ton of complexity to mapping C source to assembly.
> Also, documentation is all over the place. If a function isn't described in `man`, I have no idea where else to actually look for it.
Use of the standard library grows less and less significant as the size of the C project grows. Besides that, cppreference.com has pretty much everything.
And yeah, as others have said, a linear sequence of bytes is still a thing every CPU presents. Yes, there's cache & whatnot, but there's like precisely no way to usefully map that to any user-controllable/visible thing, because it's pretty much not user-controllable and intended to be invisible (and varies across all hardware).
I wrote Metalang99 [1] as a compile-time language that is able to perform loops, recursion, etc. It's not Turing-complete though, as the C preprocessor is not Turing-complete.