Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You know what I've learned over the years? While many people are very bad about writing C, I'm pretty good at it. So C is not a bad language; there are just a lot of bad programmers around using it.

(And if you're wondering how to write good C? Make object ownership explicit. Never have malloc and free more than a page of code apart. Don't expose data structures as API. Make errors put your routine into a defined state that the caller can understand. Use bstrings instead of cstrings.

And although I don't write much C++, the more I learn about it, the more I believe it's possible to write good C++. Most people won't spend the time to write good software, and when you do that in C or C++ it's an absolute disaster. But if you go slowly, plan, think, exercise care, and review your work regularly, you can get good code that runs fast.

You can write a safe Haskell application in 10x less time than you can write a safe C++ application, though.)



If defects are at best constant over number of lines of code, then just the extra situps C makes you do are inevitably going to create reliability issues. But we all know that it's not that simple, and that some languages are more defect-prone than others; that leaves you to make the case that C is more resilient than most high level languages.

Amusingly (just in this context), when Joe Damato makes fun of Ruby reliability, what he's actually making fun of is the terrible C code MRI is built out of.

It's interesting to look at how Apple has dealt with this problem. iOS developers write a dialect of C --- in fact, a dialect that is nominally less safe than C++. But idiom in iOS keeps most iOS programs away from unsafe code patterns. You can try to tokenize a string in an iPhone program by taking it's char* (even that is a pain to get because of character encoding) and then strsepping it, but the whole rest of the programming environment works against you when you do.


Hail, god amongst men. Once upon a time I thought I was a very good C programmer. Today I know myself to be a terrible programmer. I surround myself with safety mechanisms such as -Wall -Wextra -Werror and the clang analyzer, but even these tools cannot stop me from shooting myself in the foot time and time again. Please enlighten me, such that I may learn to write safe code in an unsafe language infallibly.


The only effective safety mechanism for C code is size. You must treat everything you write in C as though it's a tiny standalone library, and then build your application from those libraries. "Frameworks" do not work here. (Unless, that is, you're going to go insane and implement a refcounting gc and double-indirection pointers, like C++ programmers do. That works, but at that point, you've lost all speed and simplicity benefits and you might as well just use your favorite Java substitute instead. Remember: you write C because you want other stuff to use it. When you implement your own memory model and semantics, you lose that. And then you have if statements, integers, goto, and segfaults.)


Each time you put a bug in, make sure to take it out afterwards. Nobody cares how many bugs you put in, only how many are left :)


Oh! It's so easy. I can't believe I didn't think to do that before.

... but every time I do find a bug, I am surprised to find it. Thus it stands to reason there are bugs I have not yet found. How do I find all of them?


Ah, well you seemed most concerned about the sheer quantity of foot-shot-off type bugs you put in, so I thought I'd put your mind at rest about that first. Sadly, that part is inevitable.

As for finding them before anybody else does, I suggest all of the following, which is what I do, because I've found it to work for me:

* Never run outside debugger unless you have previously verified inside the debugger that the run will work - this ensures that you are in a position to fully investigate any problems that might occur. (Some programs can't be verified ahead of time, because they're non-deterministic. (Hopefully due to non-deterministic sources of input, rather than anything in the code!) You just never run these outside the debugger.)

* Never run optimised build if you can help it (this is what the QA department and your users are for :) - again, this ensures you are in a good position to investigate any issues you discover. (Note - you should feel confident about using the debugger with an optimised build, most likely using the disassembly view, but I figure life is too short to be doing this all the time.)

* assert, lots, about everything, particularly pointers into buffers and indexes into arrays.

* -Wall, -W4, -Whatever

* Investigate memory manager's maximally-anally-retentive mode. If it doesn't have one, find a memory manager that does, and use that one instead. Switch it on and fix every complaint it might have.

* Find every debug option and #define for every library you use, and switch all of them on.

* Try to avoid having any multithreading.

* Make sure you know as many dark corners of the language as possible, and commit them to memory, so that you'll be able to spot them when people start making use of them accidentally.

* Add in some kind of crash dump/stack trace/etc. display to your program, so if it should crash during actual use then you stand some chance of getting some useful information back. (Avoid frame pointer omission for this reason.)

Unfortunately I can't guarantee that this will necessarily work, but I've found the above to at least have helped me minimise the sort of creepy, freakish bugs that you only get in C and its ilk.


Care. I recommend "Programming Pearls" as a good introduction to this concept.


How careful are you with your code? What would you be willing to stake on that answer?


I'm not saying I care about my code. I'm just saying that one can write bug-free code if one takes the time to do it.


Do you have a piece of code you feel confident about, such that you'd be able to say "here is an existence proof of carefully-written resilient C code of some significant length"? I'd like to take you up on an offer to validate that proof.


I do, but it's unfortunately internal at work. Everything I write for fun has so many library dependencies that you just have to cross your fingers and hope that it will all work as documented :)


Very true. I think most hate for C is really misplaced or for completely the wrong reasons.

I like to think I'm a good C programmer, and I use most of the techniques you describe. But lately I've been wondering whether I'm not actually coding object-oriented code in an inefficient manner. Do you try to somewhat avoid falling into an OOP pitfall, or do you embrace OOP and if so, what reasons do you have to use C over Java or C++?


C is a language for people that care about programming. Like, you treat it as a lifestyle, not a career or side activity. You read books on it cover to cover. You continually seek to simplify and make your code more clear.

If that describes you, it's a damn fine tool.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: