It's reasonable that such people would also be interested in design aspects of languages, and UB in C is in that field. Though I would argue that a lot of it was originally accommodating old CPU architectures without compromising performance too badly, and about as much a "design choice" as wheels being round...
There were a few high-profile "scandals" around GCC 3.2 (IIRC) because the compiler finally started much more aggressively using UB in optimizations, which was a reason that lots of people stayed on GCC 2.95 for a very long time. GCC 3.2 came out in 2002.
In the C ecosystem, the compiler gets to define what UB means. They broke compatibility with their previous UB semantics, then blamed the language spec.
It really doesn't though. The current revision of the ISO/IEC 9899 standards document gets to define it, nobody else.
The compiler / os / hw platform are free to define the behavior of those things. Leaving them undefined at the language spec is the mechanism that allows them to be defined by the underlying system. C has worked this way since its initial release.
Every company keep harping on about safety and being exposed (being in the news): so the narrative against 'unsafe' is up the wazoo.
The new world is basically a bunch of city dwellers who haven't seen raw nature and you show them a lawn mower, they freak out. Blades that spin?!?!?! Madness!!
Can't talk about C without CVE.
If you think C is the problem, you'll come to the eventual conclusion that humans are the problems, and greed. Don't hate the player, hate the game etc.
C was invented so you don't have to write assembly. It wasn't invented to expose devices to billions of other devices.
I have lots of my code running day-in, day-out on literally hundreds of millions of machines. The approach to "getting it working" is exactly OP's.
I'll admit to being pretty defensive and anal in checking values and return-codes (more so than most, I suspect), and I'm a firm believer in KISS principles in software engineering ("solving hard problems with complicated code is easy, solving them with simple, understandable algorithms is the hard bit") but generally there's no real difference in approach to the code I write to work on my workstation, and the code I write to work in the field.
It did make you write robust and defensive code, though...
There are more things in heaven and earth, Horatio,
Than are dreamt of in your philosophy
You've probably been churning out possibly malformed code for years. Now you're becoming aware of your shortcomings. This is usually considered the transition from intermediate- to senior-level programmer.Understanding three important concepts properly in C allows one to easily identify what can/cannot result in UB viz. 1) Expressions 2) Statements 3) Sequence Points and "Single Update Rule". It is not that hard at all.
I wrote about it here with links to further reading provided - https://news.ycombinator.com/item?id=48144734
Compilers might have bugs where the spec is supposed to work but it doesn't, and many extensions without standard equivalents, or implementation-specific behaviour where undefined things in the standard do get assigned a meaningful outcome.
The real answer is that proponents of languages like C seem to completely disregard the dangers/difficulty of hitting/difficulty of fixing UB. Proponents of languages like Rust overstate it instead. Pointless wars/drama is fun to read and gets clicks.
2. You don't really appreciate the issue. Signed integer overflow is undefined. If you check for that overflow after the fact the compiler can, and demonstrably has pretended that the overflow can't happen and optimised away your overflow check.
You may not even come across that failure mode to know to 'fix' it. And good luck finding the issue unless you know about UB and what the compiler can and will do in such situations.
Although I haven’t noticed a spike the last 6 months, just a slowly increasing realization that C isn’t fit for humans and should go the way of asbest: Don’t use it for anything new, and remove it where it already exists, unless doing so would be too expensive or disruptive.
Personally I like C because you should have a good idea of what it's going to do. Other languages feel like a black box, and I start having to fight them far too often. But I say that as a hacker of low level stuff, not as someone who's paid and working on higher level stuff, so that is probably a niche view.
tl;dr: C defined language semantics, and leaves some behavior undefined. Each system that C is ported to has the ability to define the behavior however it wants.
This blows the mind of PL folks every decade or so.
It’s cool that we have portable methods and formal language semantics for stuff like memory fences and atomics now, but that sort of thing worked fine in C back in 1970 (or else unix would not have worked). You just needed to read the target machine’s manual when porting stuff.
The modern version is arguably better, but also arguably worse. Does anyone else remember when the JVM got this stuff wrong, making safe multithreaded code impossible, and then later had to break compatibility with the language spec?
You could claim that we can’t trust hardware folks to get instruction semantics right (this is demonstrably true), but duplicating and slightly modifying the specs in your language spec doesn’t actually fix the underlying hardware bugs.
Yeah, getting old… I’ll go find a cloud to yell at.
After switching to Rust five years ago I agree with all the Rust hipsters as far as disliking those languages go.
I just don't talk about it a lot. If every Rust person I know that was a C/C++ developer before was as outspoken about what they think of the latter, you'd see that these people are a majority.
We're just old hands who like to use stuff that works. And most of us don't get attached to code or languages.
It's also difficult to admint to yourself that you were never in command of a language as far as UB/other footguns go, as much as you thought. Or ever, for your enire career. For me that self-realization about C/C++ (enabled by Rust) was a turning point.
Lately you can read about the dichotomy re. AI use.
I.e. developers who define them themselves through what they build/ideas are embracing LLMs; for what they can do.
I.e.: I am what I build.
Whereas developers for whom software engineering is a craft that defines them hate them openly.
I.e.: I am how I build.
Now this seems to suggest to me that maybe Rust developers who openly hate C/C++ squarely belong to the latter group whereas the silent ones belong to the former. It's builders vs programmers. Just different world views.
Also you can not dislike something and still not speak about it. Because you decided to not care.
Just like TypeScript can't get rid of JavaScript WATs.
I trust your historical C usage was more productive than that..