I was about to
sweep in and complain about poor coding.
Whenever I write kernel modules in C (Linux ugh), I find myself spending far too long detangling unintuitive preprocessor crap that has no place in 2021. When implementing secure protocols, most ciphers allow in-place operations, but usually headers need to be prepended and you will never find a solution to this problem that permits for the headers to remain memory aligned or for the buffers to be encrypted do.
This means to effectively make protocols which encapsulate higher level data, good buffer management is necessary. And while C allows you to do anything you want, as efficiently as you want, almost all solutions to the problem tends to lead towards reimplementing object oriented language features... usually in preprocessor macros or using crazy compiler extensions for tracking offsets into buffers based on their positions in structs.
There is also the whole game of kernel buffers. Since the kernel is in privileged mode, performing allocs and frees is frowned upon. The structure of the kernel memory space is expensive and dangerous to randomly allocate memory, especially if it may trigger the kernel to need to further allocate memory beyond its initial pool. Since the MMU is mostly bypassed in this mode and since C memory management generally is not relocateable, the only real solution is to overprovision needlessly.
I could (and probably should) write a book on all the numerous problems related to kernel development as well as the endless caveats of coding kernels in C, but let me simply say that while good C code is possible, it’s rare and far too many trivial tasks are managed manually and repetitively when coding C.
I don’t particularly care for the syntax of Rust or Go. But both languages run with a great concept which is... if it’s a very common task that can be added to the language with no real additional cost, do it. As such, both languages understand strings, buffers and data structures. There is no need for disgusting hacks to implement things like macros that are all hacks to support something as trivial as foreach.
C could fix these things as well. But it’s a conscious decision by the people steering the language to keep it as it is and to leave it to libraries and compiler extensions to do it instead.
I love C because if I want to write a new C compiler, I can make something usable and likely self-hosting within a few hours. But this isn’t the characteristic of a programming language I would want to use in 2021. If I were to spend my time on such a project, the first thing I’d do is build extensions for strings, buffers and data structures ... and it wouldn’t be C anymore.
Oh... and most importantly, I would drop the preprocessor and add support for domain specific language extensions. And I’d add proper RTTI. And I’d add an extension for references. And of course relocatable memory. And probably make ...
You know what... I don’t think I’d do anything other than bootstrap the new language with C and then basically just ignore the standard from there :)