Readit News logoReadit News
fabiensanglard · 6 years ago
I feel like I wrote that a decade ago. Wait. Damn. It WAS a decade ago.

Amazingly the list is still relevant. I will try to check out the new suggestions on this thread.

sandov · 6 years ago
Have you read "C Programming: A modern approach" (2nd ed)? And if so, what do you think about it?
wmwragg · 6 years ago
I've found "Understanding and Using C Pointers" by Richard Reese, a really wonderful book.
ExtremisAndy · 6 years ago
So glad to see this little gem mentioned! I have many books on C, but this is the only one I've ever read cover-to-cover. Clear and to the point, and no fluff/silliness. One of my favorite programming books ever!
polyphonicist · 6 years ago
Has your book recommendations changed in this decade? Would you recommend different books today?
fabiensanglard · 6 years ago
No, I think these books are still a decent recipe for a good start.

There are a few mentioned on this thread I have not read yet so maybe these will change my mind.

ternaryoperator · 6 years ago
In the 90s, most seriouc C programmers knew about these books. They were the core books most devs relied on and referred to. They're all good.

I disagree with this comment: "No website is as good as a good book. And no good book is as good as a disassembly output."

There are many websites today that are excellent. And there are many websites that cover obscure topics not found in books.

Finally, I think it's important to move past C89 to at least C99. I realize in 2011 (the date of this post), that was less feasible. But today, there is little reason for most projects not use the advances found in C99.

hazeii · 6 years ago
Personally (3 decades+ journeyman C), I find lot of the advances are often about trying to get people out of bad practices (e.g. stdint.h in C99 to fix portability issues between 32 and 64 bit).
xscott · 6 years ago
The names in stdint.h are ok, but the way they play with library functions like printf() and scanf() is not so great. Given an int64_t value x, each of these works on some platforms and is wrong on another:

    printf("here's your int64_t:  %ld\n", x);
    printf("here's your int64_t:  %lld\n", x);
And the portable way using inttypes.h is really ugly:

    printf("portably int64_t:  %" PRId64 "\n", x);
There's another religious argument to be had over size_t vs ssize_t, but that can wait :-)

VonChair · 6 years ago
I think it's important to push forward with getting people out of bad habits. In a lot of cases, the only way to do that is to force it. I don't often agree with things Apple does, but their forcing people to use x64 is similar to this I think.
imron · 6 years ago
> But today, there is little reason for most projects not use the advances found in C99.

Does visual studio support c99 yet? Last I heard MS wasn’t interested in supporting it.

xeeeeeeeeeeenu · 6 years ago
It supports most of it. Useless stuff like VLA is still uninmplemented though.
zelly · 6 years ago
You can use clang on VS
hazeii · 6 years ago
Really? No longer an MS user but occasionally my code gets ported to Windows so would like to know more.
anonsivalley652 · 6 years ago
Nuance is needed. Multiple sources form the overall picture. I found that doing hard things in an embedded or conventional shipped product team is the best way to learn, and that working with effective people who used a particular language reasonably defensively and obviously for maintainability contributed the most code value.

For example, I taught myself Pascal, C, C++, assembly and Java (badly) before attending undergrad. The good thing about the ugrad program I had was that there were SGI, HP-UX, Solaris and Linux boxes such that writing portable C was essential.. you couldn't turn in a project if make didn't work on every platform because they wouldn't say which one they would use ahead-of-time. Then, I had an embedded internship at GPS manufacturer to work on 900 Mhz and 2.4 GHz radio firmware where a C++ subset was used on a codebase that spanned about 100 products. Also, lots of refactoring test/flashing tools was required because of commented-out code remnants were checked-in and 2000-line megafunctions because interns just banged-out code without any enforced coding standards.

fao_ · 6 years ago
> And there are many websites that cover obscure topics not found in books.

Yup. Are there any books covering the same content that ctyme does? (http://www.ctyme.com/intr/int.htm)

pansa2 · 6 years ago
Ah, the famous “Ralph Brown’s Interrupt List”. It was actually published as a book: https://www.amazon.com/PC-Interrupts-Programmers-Reference-T...
fao_ · 6 years ago
It's unfortunate he doesn't list the POSIX system interface, which has personally become an absolute boon:

https://pubs.opengroup.org/onlinepubs/9699919799/

You can search it using duckduckgo with !posix, too.

Something else I've found infinitely useful when digging into musl libc or doing assembly programming, is the SYSV x64 ABI: https://refspecs.linuxfoundation.org/elf/x86_64-SysV-psABI.p...

chandlore · 6 years ago
Thanks for the link to the POSIX docs, looks very useful. More recent specs for the x64 ABI can be found at https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
wwweston · 6 years ago
One of the things I tend to think about these days is return on investment. I spent several years at the beginning of my career being a bad and then mediocre C programmer, and once I found a few other languages, I got the sense that being a mediocre-to-good programmer in these languages would be much easier, and that seems to have been borne out.

Late into a career investing in other areas, what's the advantage of becoming a good C programmer? Especially in a time where Rust and Go are viable options?

jason0597 · 6 years ago
Rust isn't viable for embedded platforms, at least not yet. It's not as easy to compile it to the most obscure ISAs as C, and the little support it has for stuff like STM32 is restricted to just that group of microcontrollers and doesn't support the entire ARM range. Maybe in the future? I'm looking forward to that day!

Go is probably never going to run on microcontrollers due to its very big overhead.

C perfectly matches on top of the hardware of a processor. Every single design decision about C was made with the computer in mind. Memory, pointers, stack, call stack, returns, arguments, just everything is so excellently designed.

Even Linus Torvalds says so! https://www.youtube.com/watch?v=CYvJPra7Ebk

If I were to make one change to C, it would be to completely rip out the #include system and bring a proper modules system. Apart from that, it's pretty much perfect.

zenhack · 6 years ago
> Every single design decision about C was made with the computer in mind.

The only problem is that computers have changed a bit in the last 50 years, and C largely hasn't. There are a couple issues:

First, C was designed for single-pass compilers, because the PDP-7 it was designed for was too small to actually run much fancier of a compiler. So C is seriously sub-optimal for optimization in a lot of ways (because the assumption was you weren't going to do compiler optimizations anyway), and there are some user-visible warts like forward declarations that are completely unnecessary today.

Second, the relevant questions with regard to CPU performance have changed a lot. Most notably:

- CPU performance has completely outstripped memory perf, so memory hierarchies and locality are everything

- Parallelism everywhere. Multiple cores, but also deeper instruction pipelines and other such things.

The way those things map to C is completely implicit; they don't show up in the language at all, and getting the machine to do what you want requires knowing things that the code wouldn't suggest at all.

I think if the same people had designed a language for a similar niche today's hardware, a lot of things would be different.

sedachv · 6 years ago
> Every single design decision about C was made with the computer in mind.

A computer. The PDP-11. C was a terrible fit for a lot of the popular contemporary architectures when it was designed (PDP-10, Burroughs large systems, UNIVAC 1100, CDC mainframes, HP 3000), and continued to be a very poor fit for many computers in the 1980s (segmented 8086 and 286, 6502, AS/400, Lisp Machines except for Xerox, Connection Machine, Tandem, Novix/RTX, Transputer, etc.).

billfruit · 6 years ago
While it is true that C perfectly matches the hardware, it imperfectly matches the rich software abstractions which are needed for moderate and large software. The lack of namespaces, sane object creation, destruction features etc, makes programming tedious. A large proportion of code in many large C programs go into recreating imperfectly the features that are by default provided by richer programming systems, and that repeats for every large program you do. It quickly becomes boring and unenlightening, to recreate an exception handling mechanism or data structure implementation for the nth time. Why would anyone not prefer not having to focus on the mere infrastructure, and rather direct directions on the interesting problems to be solved.

Another thing is that large C code bases tend to become ensconced in layers of preprocessor macros, which I think is a hack-y way of doing things.

totalperspectiv · 6 years ago
TinyGo recently became an official project and seems extremely successful.
manfredo · 6 years ago
> Go is probably never going to run on microcontrollers due to its very big overhead.

My employer runs go on micro controllers. Definitely suboptimal, but as long as the cost of increasing hardware capacity to accommodate Go is feasible then it's a viable option.

anonsivalley652 · 6 years ago
> Rust isn't viable for embedded platforms, at least not yet.

no_std allows the important hooks of panicking, output and allocation to be implemented by the user. It's also very easy to put in hard-coded pointers that represent memory-mapped hardware. And there's no GC. Furthermore, it's entirely possible to convert only a portion of a project to using Rust while working to gradually to replace/reimplement.

> If I were to make one change to C, it would be to completely rip out the #include system [preprocessor] and bring a proper modules system.

Congratulations, you've just reinvented Java, D, Rust and Go.

> Apart from that, it's pretty much perfect.

This seems like a religious opinion rather than having understanding of different paradigms. Have you been paying attention to why Java, Erlang, Go, Rust and exist? Rust has numerous advantages over C that eliminate entire categories of problems without sacrificing speed. If you can't see that, then maybe you don't want to see it.

GuB-42 · 6 years ago
C is still king in embedded systems. It is also great at making you aware of the machine. In C, very little is happening behind the scene. If you want something to happen, you need write some code. Objects will not initialize themselves, allocated memory will not free itself, no smart reference mechanisms, just explicit pointers. This understanding of the machine will help understanding why higher level langages behave the way they do.

But anyways, programming skills is not so much about the language. A good programmer in one language will be a good programmer in any other language very quickly. But still, if I have to hire a programmer for a project in a language he doesn't know, I will tend to prefer C programmers over those who only use higher level languages. The reason is that C programmers may do things that are not pretty, but they usually understand what they are doing, people who are only accustomed to some higher level language may come up with better designs, but write code that make no sense.

Mike345845 · 6 years ago
> It is also great at making you aware of the machine. In C, very little is happening behind the scene.

This is not true. It hasn't been true for decades. C is an abstract high level language on modern processors.

https://queue.acm.org/detail.cfm?id=3212479

Deleted Comment

edoo · 6 years ago
Language fluency is very important but real programming is program architecture. Learning C++ or spending time with object oriented paradigms in general will boost your C abilities.

Deleted Comment

kragen · 6 years ago
If you are troubleshooting software problems in any language (except, usually, Java), sooner or later you dig down and hit C or C++. In those cases knowing C means you can solve the problem.

There are a lot of libraries written in C, like, thousands in Debian alone. You can use them from any language, but sometimes you need to write a little bit of glue C to get that to work. Sometimes it's less painful to just write your program in C++ or Objective-C so you don't have to debug your glue C.

If you want to write a library that can be used from any language, basically your options are C, C++ (but realistically its C subset), and Rust. Getting things to work all the time is easier in Rust than in C or C++. Getting things to work some of the time is easier in C.

But for most of these things it's probably adequate to be a mediocre C programmer. Unless your mediocrity is manifested in spending a week on tracking down a bug that should have taken an hour, maybe.

firethief · 6 years ago
> Getting things to work all the time is easier in Rust than in C or C++. Getting things to work some of the time is easier in C.

I think this is a good generalization of the learning curves of the languages, but not necessarily productivity for an experienced developer. Rust has modern amenities like pattern matching, generics and a package manager.

derekp7 · 6 years ago
For me it is a smaller dependancy stack. For example I needed some tooling that worked on RHEL/CentOS, back to version 4.x and 3.x (yes, I know). Also, someone at work wanted me to get into Swift... They had Ubuntu packages but nothing for RHEL or Fedora (that may have changed now though).
kbenson · 6 years ago
If you can spare the overhead, Perl is a good option for some of these. Much of the CPAN ecosystem will still work, and anything written that doesn't require much/any external modules it will almost definitely work with no changes. There are plenty of Perl scripts kicking around from that time, and earlier.

The biggest problem would likely bad code quality standards of earlier periods (lots of budding programmers in the dot com boom wrote a lot of poorly done code that survives today, which is responsible at least in part for Perls reputation as write only), but if you're just deploying your own code, that's less of an issue. Perl can be written to be readable and obvious, it just takes control. In that respect, I imagine it's a lot like C.

saghm · 6 years ago
No idea when they were added, but there are Fedora packages for Swift now under the name "swift-lang". I don't use Fedora personally, but from what I can tell, they should be available in the default package repositories with dnf.
Waterluvian · 6 years ago
My take is this:

C is necessary in some paradigms/domains. But that list has been shrinking as other languages are born and mature.

Learning C, like learning most things, will still certainly lend itself to lots of things you do, even if you're not using C.

Why learn C? Because you want to do stuff on that list or because you feel like it. Why not learn something else instead? It may very well be that there's more worthwhile things to learn depending on your goals.

zelly · 6 years ago
> Late into a career investing in other areas, what's the advantage of becoming a good C programmer? Especially in a time where Rust and Go are viable options?

It is the most popular programming language. There is a lot of code written in it. Most jobs involve maintaining extant code. So it's good for that. It's safe to say there will be a need for C programmers for the next 100 years.

fortran77 · 6 years ago
Oh come on now. I will develop in "safe" languages where possible (my favorites are F# and Erlang), but when I need to do something on the hardware, I still use C (and C++). Rust and Go are not viable options for everything, especially when you need complete control.

Why does the Rust community have to make every discussion about Rust?

UK-Al05 · 6 years ago
What can c do that rust can't?
cozzyd · 6 years ago
The C ABI is still king.
aphextron · 6 years ago
Why does everyone always suggest K&R? I really don't see the big deal. It's short, contains only trivial toy examples with no real world application, and touches almost nothing on actual project architecture or best practices. I bought it expecting to learn to write programs in C but it's really just a reference manual on syntax.
aikah · 6 years ago
> Why does everyone always suggest K&R?

Because it's the best no bullshit book to learn C, period. Especially coming from garbage collected languages. It's not going to teach you valgrind or GDB, or even compile and link C programs but it will certainly teach you how to write C programs.

> only trivial toy examples with no real world application

Re-implementing POSIX commands is writing real world applications.

> and touches almost nothing on actual project architecture or best practices.

On what platform? Linux? Windows? Mac? tool chains are so different on all these platforms that it wouldn't make sense to spend time on that. That books is about C, not learning autotools and other horrors.

fabiensanglard · 6 years ago
In short: It is a great starter. The book is so tiny it won't discourage people and get them going in no time.
Timpy · 6 years ago
> It is all you need to know about C…for the first few weeks.

It seems the author was aware of this. Isn't syntax a good place to start for a new language?

globular-toast · 6 years ago
> trivial toy examples with no real world application

It teaches you how to write malloc. Plenty of the examples have real world applications. If you want a book on architecture then get a book on architecture. K&R is about C.

yesenadam · 6 years ago
This is a great list of books - at least, I found the same ones were the most excellent. Also I really learnt a lot from 21st Century C (The author here said they wanted to stick to C89, which is fair enough.)

>To read great C code will help tremendously.

But then he just gives examples of games I don't know and am not really interested in. Anyone know some non-game C that is, I suppose, well-known and wonderfully-written?

Also, am learning about writing APIs, any good books or talks about that people could recommend, or examples of particularly good ones in C? (I'm particularly interested in maths/graphics-type stuff.) Thanks!

jraph · 6 years ago
I find the source code of the Netsurf browser really beautiful:

- https://netsurf-browser.org/

- https://source.netsurf-browser.org/netsurf.git/tree/

Including the sub projects, for instance:

- https://source.netsurf-browser.org/libcss.git/tree/

- https://source.netsurf-browser.org/libdom.git/tree/

It feels immediately obvious and understandable, which is quite impressive for a browser. Everything is well documented, well separated, the code is clean and seems simple, functions are small, etc. I am really impressed. I'd want to work on such code. I have never worked on it though, and I am not connected in any way to this project.

needs · 6 years ago
Very well written code indeed. Thanks for the links. They could make error management less bug prone by using goto, but it's definitely high quality C code nonetheless.
eindiran · 6 years ago
The sqlite codebase is well-known for being a large, well-written C codebase:

https://github.com/sqlite/sqlite

The tests in particular are very impressive.

Some other notable C codebases: Redis, LuaJIT, FreeBSD, Memcached -->

https://github.com/antirez/redis

https://github.com/LuaDist/luajit

https://github.com/freebsd/freebsd

https://github.com/memcached/memcached

fanf2 · 6 years ago
PostgreSQL’s source code is also really good. https://git.postgresql.org/gitweb/?p=postgresql.git;a=tree
jacquesm · 6 years ago
Varnish and the Linux kernel should be in that list as well I think.
fabiensanglard · 6 years ago
I recommend git source code which was pretty neat last time i checked.
rhoyerboat · 6 years ago
recently I started working on a module for nginx and have developed a full-blown crush on the module loader and its relationship with core functionality. haven't seen anything else quite like it, in C, that is. major newb talkin'

also plan9, its nice to read some kernel code that hasn't been tortured by practical requirements for decades.

atq2119 · 6 years ago
The core Linux kernel is well-known and mostly well-written C.
ndesaulniers · 6 years ago
I'd say "advanced" C, not necessarily "well-written" C. There's certainly a lot of C in it, and I'd bet it's the largest open source C codebase.
anaphor · 6 years ago
"C Interfaces and Implementations" is another one that comes highly recommended.

https://sites.google.com/site/cinterfacesimplementations/

sn9 · 6 years ago
This book is fantastic to tackle for anyone comfortable with C at the level of K&R. A great second book on C.

And one of the few examples of literate programming one might come across!

AceJohnny2 · 6 years ago
The K&R book was for decades my gold standard of a programming book. Perfectly clear and concise, its one notable failing being that it's obsolete.

The Rust Programming Language [1] has since equalled and surpassed it in my mind. Hats off for Steve Klabnik & Carol Nichols :)

(note, I'm not saying Rust is a better answer than Fabien's recommendation, just that its book is as high quality as the excellent K&R)

[1] https://doc.rust-lang.org/book/