Over the last few days, there has been this… debate over at Twitter sparked by a claim that you cannot be a good programmer without knowing C. You obviously can be one, but there is some nuance in what “knowing” C is truly about. Here is my take on the matter.

Let me repeat this first: of course you can be a perfectly good programmer without knowing C. Knowing a language doesn’t make or break a programmer, and there are great programmers out there that don’t touch C. However, knowing C says something about your journey.

If you know C well, it means you’ve dealt with pointers and managed memory by hand. It probably also means you know the difference between system calls and library calls. And it might also mean that you know about FFI. Let’s look at this trinity and why these are important.

🧠 First, memory. When learning C, you must deal with pointers, malloc, and free, and you must learn how these are put to use. You also may learn how to debug a segfault and probably use tools like Valgrind to find memory errors.

None of this is trivial. Saying that “a pointer is just a memory address; what’s difficult in that!?” misses the point (get it?). Knowing what a thing is is really different from knowing how to use that thing. I covered something similar back in my post about Rust’s Into trait.

But more importantly, pointers and memory management are not a “C thing”. These concepts show up in pretty much any language. For example, both Java and Python differentiate primitive types from objects… and, guess what, object references are essentially pointers.

Without knowing pointers, it’s hard to reason about pass-by-value vs. pass-by-reference semantics. Without knowing memory management, you can’t easily tell whether your code makes a reasonable use of memory.

📣 Second, system calls vs. library functions. For example, how do read and fread differ? They are not the same thing and using them interchangeably can lead to performance problems. Reading bytes one by one with read is very inefficient but isn’t with fread.

When learning C, you often have to read manpages because they are the primary source of documentation for the C APIs. In doing so, you probably have noticed that certain manpages are in section 2 (system calls) and others are in section 3 (library functions).

Every language must issue system calls but not all languages expose them as clearly as C does. The distinction exists in higher level languages but it is more subtle. If you aren’t careful, you can introduce performance problems like the one in my post on deleting directory hierarchies.

⚙️ Third, the Foreign Function Interface (FFI). Almost every language in your system has to end up calling into the C library to execute system calls. If you have learned C, you have probably also learned about stack frames and how a binary (ELF or whatnot) is put together.

This knowledge is useful because, as I said, every language—except for the stubborn Go—has to talk to C for certain operations. And this interface isn’t always zero cost. Knowing the costs helps write more efficient code.

💡 So there they are. The three major topics that you are likely familiar with just by knowing C well. Of course you can be a good programmer without knowing these topics deeply, but being familiar with these will help you engineer better systems.

Paraphrasing Joel Spolksy’s article titled “The perils of JavaSchools” from 2005: there are only two types of programmers: those that know pointers (and recursion), and those that don’t.

This aligns with my experience after interviewing 100+ candidates: there is a stark contrast between those that don’t known anything about memory management and those that do. I couldn’t care less about what language you choose, but I want to see if you know how things work.

Because, remember: these three topics have nothing to do with C per se: they are concepts that apply to almost any language. For example, you also deal with memory in Rust via Box, but a Box is is more opaque than explicit malloc and free calls.

So: don’t be worried if you don’t know C, but also don’t be afraid to learn it! Just, please, don’t use it to start any new project. Keep C to yourself as a learning exercise, or leverage it as a tool to deal with legacy codebases.