I've been programming in C for over 20 years now. I've written C compilers, C debuggers, other languages, games, clients, servers, you name it. Dog-eared editions of K&R and Steele decorate my shelves. So I know C. And yet, I'm sick of it. SICK.
So it was with some trepidation that I read a blog on why every programmer should learn C. Turns out it's good for a laugh if you're a professional developer, though the author probably didn't intend it that way. This rebuttal makes a bit more sense, but still doesn't capture the essence of why C should go the way of the dodo. So let me turn it around. Here are 5 reasons why developers who know and use C now should not just use something else, but UN-learn all the bad things they learned in C.
1. Memory allocation. I could write a whole article just on this one. A book. Maybe a small wing of the library. Memory allocation and deallocation is the bane of my existence. Either you allocate too little and write off the end, or too much and waste it. Then there's the question of whether to zero it or leave it uninitialized. But freeing memory is the worst. Entire toolkits have been written to help you make sure you have freed every little bit you allocated, never use it after freeing, and God forbid, never free it twice. To add insult to injury, allocations and frees are slow in C, very slow. I don't want to even think about all the special cases I've had to put in to *avoid* memory allocation and use stack or pre-allocated structure space if the problem size fit. Well, I've got better things to worry about. Whoever invented garbage collection should win a Nobel.
2. Multi-threading. I used to like C, really. Until I started to develop and maintain multi-threaded servers with it. C doesn't help you at all with protecting data from access by conflicting threads. Every intuition you had from single-threaded days is wrong. At least Java has the synchronized keyword, and a documented (but weird) memory model, but even that falls apart on massively parallel machines unless you use the new javax.concurrent stuff. Flashback - in C: 1 week standing up (true story) in a data center debugging a deadlock problem in a simulated production environment. In Java: Ctrl+Break! Ahhh.
3. Pointers. Pointers are insidiously evil; there's just no polite way to say it. Months of my life are just gone from debugging problems with wild pointers. I used to go for all the tricks, such as incomprehensible casts and unions and offsetof and reusing the last couple of bits for flags, and all that. It's just not worth it. Statically typed references are your friend.
4. Premature optimization. Speaking of tricks, have you ever wasted any brain cells wondering if *p++ was faster than p[i]? Have you spent time trying to do shifts instead of multiplies, or reversing for loops to try and make them run faster? Agonized over the speed of passing parameters as opposed to filling in a structure and passing that? STOP IT! Algorithms are the key to speed, and developer productivity is the key to algorithms. Get the idea that you can make your program any better or faster with little tweaks out of your head. Yeah, there are a few cases where maybe... no, just don't go there.
5. Tests. What's your favorite C unit testing tool? Umm..... can't think of one? Unit testing must not be important then, right? Or too much trouble. Hard to keep up to date. Waste of time. You could spend that time shaving .001% off your execution time. Or debugging that problem that only occurs with 100 simultaneous users, in the data center, on an optimized image with no symbols.
I could go on, but 5 is enough for now; I feel better already. C was wonderful... in 1984. It amazes me that new code is being written in C, even today. C++ is only marginally better if you ask me. If you want to learn something old, try Forth, Lisp, or APL. At least those can teach you some different and elegant ways of thinking about programming.