I think every graduating student should work on a non-trivial application in plain C for a year before moving on to another language.<p>It makes you exceptionally paranoid about failure states and practically requires a bit of thought and planning before attempting any non-trivial change.<p>The mindset of "it's fine to ignore all error conditions and let the default exception handler print a stack trace to the user" results in software that is annoying <i>to the user</i>.
Reliable is not the same as portable, which is not the same as well-defined according to the language spec.<p>The consequences of doing something incorrect or nonportable is sometimes that the expected behavior occurs. This can be validated by testing on the couple of platforms (or just one) that the program supports, and kept working.<p>Another thing we need to consider is that reliable is not the same thing as robust, let alone secure. A program that appears reliable to a user who uses it "as directed", giving it the expected kinds of inputs, will not necessarily appear reliable to a tester looking for ways to break it, or to a cracker trying to exploit it.<p>A truly reliable program not only handles all its functional use cases according to its requirements, but is impervious to deliberate misuse, no matter how clever.<p>Security flaws are found in reliable, well-debugged programs used in production by millions.
C is horrible for exploratory programming but is acceptable if you already know how to solve the problem. If one uses enums for errors, then the compiler can check for you that all edge cases are handled. You can log an error and exit(1) for unhandled cases during development which makes it feasible to turn on -Werror but not have to implement every edge case up front.<p>You can do the same thing with tagged unions to implement a poor man's sum types. It is significantly more verbose than in a language that has syntactic support for this, but you get similar compile time safety guarantees.
Though not specific to C language, C.A.R Hoare's <i>Retrospective: An Axiomatic Basis for Computer Programming</i> provides insight on why Software is so reliable in spite of a lack of application of formal verification methods.<p>Retrospective: <a href="https://cacm.acm.org/opinion/retrospective-an-axiomatic-basis-for-computer-programming/" rel="nofollow">https://cacm.acm.org/opinion/retrospective-an-axiomatic-basi...</a><p>Here is a pdf of the retrospective along with the original paper : <a href="https://harrymoreno.com/assets/greatPapersInCompSci/2.2_-_An_Axiomatic_Basis_for_Computer_Programming_-_C._A._R._Hoare.pdf" rel="nofollow">https://harrymoreno.com/assets/greatPapersInCompSci/2.2_-_An...</a>
The author started by seriously admitting the drawbacks of C. Then, somehow, he says thanks to those flaws he has to pay higher attention when building software in C, he created very reliable tools.<p>That's something I can understand because when I wanted to buy a motorbike I was advised to ride a bicycle first since it's more difficult to control. Except that the White House called recently for companies to not use non memory safe languages such as C to build software.
C suffers from a terrible case of survivor bias. C is so effective for writing all of the most critical software, that almost all software people trust is written in C. Therefore almost all critical vulnerabilities are found in C code.
I think the reliability gap is in statically typed, compiled languages versus dynamically typed languages. I think C++ is a good combination of both worlds. You don't have to type quite as much for error checking an manual management and you get a correctly typed program by default.
Until one writes a nontrivial program that properly handles -EINTR errors on every possible point, I don’t anyone should brag about their error handing prowess.<p>It is also hard to handle errors more meaningfully than instantly terminating the process at the first whif of something going sideways.<p>And once you do write such a thing, try making automated tests to exercise it!!<p>How many programs actually check the return value of close() ?<p>Sure, this sounds a bit Linux/POSIX specific. There are only a few billion devises running such code, perhaps I’m overreacting…
Is the mindset of exception handling so different than robust C code? In both cases you have to choose to diligently handle errors and check the code/docs for all cases that can come up. Writing code with the occasional try/catch block isn't too different from writing C and not checking error conditions
This text doesn’t make much sense, on the one hand the author argues that software written in C is robust, on the other hand the author admits that he has unknown bugs lurking in his own project.<p>One bug took several months to track down. This is cognitive dissonance at its finest.
1) were C programmers "better"? In sum total, pretty much.<p>2) C programs, at least the ones we use now, are a product of a lot of use and debugging<p>3) It didn't take too many debugging sessions as a C programmer to learn to program a bit more carefully.<p>4) and the more it gets used, the more error codes it encounters, and the more robust the handling gets. I think a dirty secret of software engineering isn't that the most complicated/heavily used code gets the most and most useful comments, it's that it also get the most error handling/detection code, and for the vast majority of non-core loop code: error handling ..isn't.