Alternately, stop writing code in C.
Alternately, stop writing code in C.
Oh you would like a byte? Is that going to be a 7 bit, 8 bit, 12 bit, or 64 bit byte? It's not specified, yay! Have fun trying to write robust code.
The problem is that C++ is a huge language which is complex and surely not easy to implement. If I want a small, easy language for my next microprocessor project, it probably won't be C++20. It seems like C is a good fit, but really it's not because it's a high level language with a myriad of weird semantics. AFAIK we don't have a simple "portable assembler + a few niceties" language. We either use assembly (too low level), or C (slightly too high level and full of junk).
In reality, if you're writing C in 2025, you have a finite set of specific target platforms and a finite set of compilers you care about. Those are what matter. Whether my code is robust with respect to some 80s hardware that did weird things with integers, I have no idea and really couldn't care less.
Because I want the next version of the compiler to agree with me about what my code means.
The standard is an agreement: If you write code which conforms to it, the compiler will agree with you about what it means and not, say, optimize your important conditionals away because some "Can't Happen" optimization was triggered and the "dead" code got removed. This gets rather important as compilers get better about optimization.
Still, while I acknowledge that this is a real issue, in practice I find my C code from 30 years ago still working.
It is also a bit the fault of users. Why favor so many user the most aggressive optimizing compilers? Every user filing bugs or complaining about aggressive optimizing breaking code in the bug tracker, very user asking for better warnings, would help us a lot pushing back on this. But if users prefer compiler A over compiler B when you a 1% improvement in some irrelevant benchmark, it is difficult to argue that this is not exactly what they want.
The big weak region seems to be in-order machines with smaller numbers of general purpose registers.
GCC at least seems to do its basic block planning entirely before register allocation with no feedback between phases.
In my experience, if you don't try to be excessively clever and just write straightforward C code, these issues almost never arise. Instead of wasting my time on the standard, I'd rather spend it validating the compilers I support and making sure my code works in the real world, not the one inhabited by the abstract machine of ISO C.
> In my experience, if you don't try to be excessively clever and just write straightforward C code, these issues almost never arise.
I think these two sentiments are what gets missed by many programmers who didn't actually spend the last 25+ years writing software in plain C.
I lose count of the number of times I see in comments (both here and elsewhere) how it should be almost criminal to write anything life-critical in C because it is guaranteed to fail.
The reality is that, for decades now, life-critical software has been written in C - millions and millions of lines of code controlling millions and millions of devices that are sitting in millions and millions of machines that kill people in many failure modes.
The software defect rate resulting in deaths is so low that when it happens it makes the news (See Toyota's unintended acceleration lawsuit).
That's because, regardless of what the programmers think their code does, or what a compiler upgrade does to it, such code undergoes rigorous testing and, IME, is often written to be as straightforward as possible in the large majority of cases (mostly because the direct access to the hardware makes reasoning about the software a little easier).
Like it or not, C can run on more systems than anything else, and it's by far the easiest language for doing a lot of low-level things. The ease of, for example, accessing pointers, does make it easier to shoot yourself in the foot, but when you need to do that all the time it's pretty hard to justify the tradeoffs of another language.
Before you say "Rust": I've used it extensively, it's a great language, and probably an ideal replacement for C in a lot of cases (such as writing a browser). But it is absolutely unacceptable for the garbage collector work I'm using C for, because I'm doing complex stuff with memory which cannot reasonably be done under the tyranny of the borrow checker. I did spend about six weeks of my life trying to translate my work into Rust and I can see a path to doing it, but you spend so much time bypassing the borrow checker that you're clearly not getting much value from it, and you're getting a massive amount of faffing that makes it very difficult to see what the code is actually doing.
I know HN loves to correct people on things they know nothing about, so if you are about to Google "garbage collector in Rust" to show me that it can be done, just stop. I know it can be done, because I did it; I'm saying it's not worth it.
no serious alternative
For the bigger systems where that's not appropriate, you'll value a more expressive language. I recommend Rust particularly, even though Rust isn't available everywhere there's an excellent chance it covers every platform you actually care about.
I think you could argue that Zig is still very new so you might not want to use it for that reason, but otherwise there is no reason to use C for new projects in 2025.
one compiler, two platforms, no spec
> Zig
dollar store rust