Earlier quoted context omitted.
The most common way to indicate that an error has occurred in a C function is to return non-zero. If this is done consistently, and return values are always checked, an error condition will eventually make its way up to main, where you can fail gracefully. For example: int a(void) { ... if (oops) { return 1; } return 0; } int b(void) { if (a(...) != 0) { return 1; } return 0; } int main(void) { if (b(...) != 0) { exi…
This is a brilliant example of why you'd want exceptions. Look at what you're doing for error handling, manually every time. Exceptions do the exact same thing, except: 1) automatically 2) type-safe 3) allow you to give extra detail about the error 4) tools can actually follow the control flow and tell you what's happening and why 5) debuggers can break on all exceptions. Try breaking on "any error" in your code (I d…
How can C Programs be so Reliable? (2008)
191–200 of 230 posts
Re: How can C Programs be so Reliable? (2008)
#192Earlier quoted context omitted.
You state a lot of half truths ("you'll never be able to catch all exceptions"), don't justify the assumptions and didn't handle the core of my argument (abstraction leakage). In the hurry to insult me, did you actually read my argument?
Because the core of your argument was based on a stupid rule I don't agree with! You: "Throwing DiskFullException results in abstraction leakage" Me: "No it doesn't.."
Please accept my apologies.
Re: How can C Programs be so Reliable? (2008)
#193Earlier quoted context omitted.
> The trick is to almost never ever catch exceptions. I strongly disagree. Not catching exceptions leaks abstraction layers. If I have a Prefs::save() method, I don't want it throwing a DiskFullException when the Prefs class is an abstraction of a preferences datastore. I don't care what is the final store, as long as it fits the abstraction. A well designed abstraction will catch and wrap the exception into somethin…
Librairies that wrap exceptions into something else often do a disservice to their users. In this `Prefs:save()` example, what should the wrapping library throw? A "SaveFailedException"? That's more abstract, however now I would need to go check the source code of the library, find where the exception has been converted to something else, comment out the "try/catch" statement, and rerun the program. Then I can finall…
Re: How can C Programs be so Reliable? (2008)
#194There are multiple factors that contribute, but here's a few that I haven't (to the best of my recollection) seen mentioned so far: tooling (crucial), "do the simplest thing that could possibly work" attitude brought about by (lack of) a built-in collections library and simple syntax, and lack of rapidly changing requirements during development. Tools for C are powerful, mature, and available on near every platform.…
The other day I was quite surprised to learn that the first version of memcached was written in Perl - thinking something like that should be obviously written in C, or else could never make LAMP systems faster... :)
Re: How can C Programs be so Reliable? (2008)
#195Earlier quoted context omitted.
Isn't fork the real offender, which requires Linux to overcommit by default? Disabling swap shouldn't affect that, right? Just makes your problem happen later, in a somewhat non-deterministic way. Without fork, what reason do you not disable swap? I can only think of an anonymous mmap where you want to use the OS VM as a cache system. But that's solved easily enough by providing a backing file, isn't it?
> Isn't fork the real offender, which requires Linux to overcommit by default? Maybe I'm missing something, but how does fork require overcommitment? When you fork, you end up with COW pages, which share underlying memory. They don't guarantee that physical memory would be available if every page were touched and required a copy; they just share underlying physical memory. Strictly speaking, very little allocation ha…
Re: How can C Programs be so Reliable? (2008)
#196Earlier quoted context omitted.
> Also code where you have to undo all of the work already done in the function up until that point, which can get a little tedious, i.e.:- Sorry pal, you're doing it wrong. At least, this is not the way I've done it and seen it done in large C code bases. You're supposed to have only one return statement, and one block that frees everything. For example if you initialize `foo`, `bar`, and `qux` to `NULL`. Then testi…
What you've described looks just as messy to my eyes, and I've seen all different ways to do this. You can nest under if(thing!=NULL) but then you end up with indentation creep. You can use the goto pattern if you like but some folks will tell you that goto's are never, ever to be used. Or you can do what's done above. When it comes down to it the logic is basically identical and it's just down to code formatting.
Re: How can C Programs be so Reliable? (2008)
#197Popular C software is so reliable because of enormous amount of effort spent developing, testing, and polishing it over many years - not because error handling in C is superior to that in higher-level languages. If your python script sticks around for 30 years constantly being used by millions of people - I bet it will be rock solid as well. All other things [1] being equal [2], a program written in a higher-level la…
Yes! Most software I've seen can be dramatically improved by removing exception handlers. (And then fixing the underlying problems). On the server side I prefer one exception handler which is the OS, it will kill your process, release and free all memory, file handlers, etc. Then I wrap it in a bash script / other monitoring tool, and have it immediately restart whenever it fails. As for the server itself I'll also a…
In most software I see, exception handlers are a myriad of poor implementations of "log a message, clean up state, and try/fail again" rather than the actual handling of a specific exceptional state. Many of the most frustrating bugs I've seen are introduced when an exception handler fails to clean up state and tries again with some kind of insane context or a leaked handle.
Re: How can C Programs be so Reliable? (2008)
#198Earlier quoted context omitted.
> Also code where you have to undo all of the work already done in the function up until that point, which can get a little tedious, i.e.:- Sorry pal, you're doing it wrong. At least, this is not the way I've done it and seen it done in large C code bases. You're supposed to have only one return statement, and one block that frees everything. For example if you initialize `foo`, `bar`, and `qux` to `NULL`. Then testi…
What you've described looks just as messy to my eyes, and I've seen all different ways to do this. You can nest under if(thing!=NULL) but then you end up with indentation creep. You can use the goto pattern if you like but some folks will tell you that goto's are never, ever to be used. Or you can do what's done above. When it comes down to it the logic is basically identical and it's just down to code formatting.
I am not suggesting any nesting of anything. Repeatedly checking at the same indentation level.
> You can use the goto pattern if you like but some folks will tell you that goto's are never, ever to be used.
What matters more to you, getting stuff right or repeating adages that other people have said out of context? `goto` is probably the cleanest way to do it in plain C.
> When it comes down to it the logic is basically identical and it's just down to code formatting.
No actually, it is quite a bit more than style, doing it the way alexkus has it is much much much less maintainable when it's done all over a large code base. He's got `foo`, `bar`, `qux`. What if a year later some future maintainer totally unfamiliar with the code needs to add another one? Then it's up to that person to find all of the exit paths, make sure that `foo`, `bar`, `qux` and the new thing are freed in all cases. Doing that is a lot harder if the free statements are all over the place and repeated several times instead of in a single block.
Re: How can C Programs be so Reliable? (2008)
#199"[Pointers are] arguably the trickiest concept in low-level languages, having no simple real-world analogy[.]" I'm not sure how "address" is not a good, "simple real-world analogy" for pointers. It may be that I've just internalized enough of the behavior of pointers that I'm glossing over important differences, though... I struggled with pointers long enough ago that I don't remember struggling with pointers.
I think pointer syntax in C, not pointers themselves, is what causes confusion for most beginner programmers. This post explains it well: http://objcsharp.wordpress.com/2013/08/14/the-great-pointer-...
int b, *a;
declares that "b"
and "*a"
are ints only really breaks down at casts. It does require point out that you are allocating space for the named things, not the terms...Re: How can C Programs be so Reliable? (2008)
#200Earlier quoted context omitted.
What you've described looks just as messy to my eyes, and I've seen all different ways to do this. You can nest under if(thing!=NULL) but then you end up with indentation creep. You can use the goto pattern if you like but some folks will tell you that goto's are never, ever to be used. Or you can do what's done above. When it comes down to it the logic is basically identical and it's just down to code formatting.
> You can nest under if(thing!=NULL) but then you end up with indentation creep. I am not suggesting any nesting of anything. Repeatedly checking at the same indentation level. > You can use the goto pattern if you like but some folks will tell you that goto's are never, ever to be used. What matters more to you, getting stuff right or repeating adages that other people have said out of context? `goto` is probably th…
This could be considered wasteful. You end up checking if something is NULL, if it is you jump to the cleanup code and immediately check again. Nesting may be more elegant.
>> What matters more to you, getting stuff right or repeating adages that other people have said out of context? `goto` is probably the cleanest way to do it in plain C.
Writing code in a way consistent with the team I work with and the established codebase.
>> What if a year later some future maintainer totally unfamiliar with the code needs to add another one?
Then they need to read what the function is doing and understand it before they mess with the code, just like in any other situation.
>> Doing that is a lot harder if the free statements are all over the place and repeated several times instead of in a single block.
More verbose certainly, but if the code is written in small, discrete functional blocks then it shouldn't really impact much.
He repeats frees, you repeat tests. An indenter would repeat neither but has indent readability to consider.
Frankly, don't trust anyone that tells you that they have the one true way to do things.