This Book Is Not Really about C
Please don't feel cheated, but this book is not about teaching you C programming. You'll learn to write programs in C, but the most important lesson you'll get from this book is rigorous defensive programming. Today, too many programmers simply assume that what they write works, but one day it will fail catastrophically. This is especially true if you're the kind of person who has learned mostly modern languages that solve many problems for you. By reading this book and following my exercises, you'll learn how to create software that defends itself from malicious activity and defects.
I'm using C for a very specific reason: C is broken. It is full of design choices that made sense in the 1970s but make zero sense now. Everything from its unrestricted wild use of pointers to its severely broken NUL terminated strings are to blame for nearly all of the security defects that hit C. It's my belief that C is so broken that it's the most difficult language to write securely in wide use today. I would fathom that Assembly Language is actually easier to write securely than C. To be honest, and you'll find out that I'm very honest, I don't think that anybody should be writing new C code.
I don't want to scare you away by telling you this, because I plan to make this book incredibly fun, easy, and devious. I'll make it fun to learn C by giving you projects that you might not have done in other programming languages. I'll make this book easy by using my proven pattern of exercises that has you doing C programming and building your skills slowly. I'll make it devious by teaching you how to break and then secure your code so you understand why these issues matter. You'll learn how to cause stack overflows, illegal memory access, and other common flaws that plague C programs so that you know what you're up against.
Getting through this book will be challenging, like all of my books, but when you're done you will be a far better and more confident programmer.
The Undefined Behaviorists
By the time you're done with this book, you'll be able to debug, read, and fix almost any C program you run into, and then write new, solid C code should you need to. However, I'm not really going to teach you official C. You'll learn the language, and you'll learn how to use it well, but official C isn't very secure. The vast majority of C programmers out there simply don't write solid code, and it's because of something called Undefined Behavior (UB). Undefined Behavior is a part of the American National Standards Institute C standard that lists all of the ways that a C compiler can disregard what you've written. There's actually a part of the standard that says if you write code like this, then all bets are off and the compiler doesn't have to do anything consistent. For a bit of background, C defines strings as blocks of memory that end in a NUL byte, or a 0 byte (to simplify the definition). Since many strings come from outside the program, it's common for a C program to receive a string without this NUL byte. When it does, the C program attempts to read past the end of this string and into the memory of the computer, causing your program to crash. Every other language developed after C attempts to prevent this, but not C. C does so little to prevent UB that every C programmer seems to think it means they don't have to deal with it. They write code full of potential NUL byte overruns, and when you point them out to these programmers, they say, "Well that's UB, and I don't have to prevent it." This reliance on C's large number of undefined behaviors is why most C code is so horribly insecure.
I write C code to try to avoid UB by either writing code that doesn't trigger it, or writing code that attempts to prevent it. This turns out to be an impossible task because there is so much UB that it becomes a Gordian knot of interconnected pitfalls in your C code. As you go through this book, I'll point out ways you can trigger UB, how to avoid it if you can, and how to trigger it in other people's code if possible. However, you should keep in mind that avoiding the nearly random nature of UB is almost impossible, and you'll just have to do your best.
WARNING: You'll find that hardcore C fans frequently will try to beat you up about UB. There's a class of C programmers who don't write very much C code but have memorized all of the UB just so they could beat up a beginner intellectually. If you run into one of these abusive programmers, please ignore them. often, they aren't practicing C programmers, they are arrogant, abusive, and will only end up asking you endless questions in an attempt to prove their superiority rather than helping you with your code. Should you ever need help with your C code, simply email me at firstname.lastname@example.org, and I will gladly help you.
C Is a Pretty and Ugly Language
The presence of UB though is one more reason why learning C is a good move if you want to be a better programmer. If you can write good, solid C code in the way I teach you, then you can survive any language. On the positive side, C is a really elegant language in many ways. Its syntax is actually incredibly small given the power it has. There's a reason why so many other languages have copied its syntax over the last 45 or so years. C also gives you quite a lot using very little technology. When you're done learning C, you'll have an appreciation for something that is very elegant and beautiful but also a little ugly at the same time. C is old, so like a beautiful monument, it will look fantastic from about 20 feet away, but when you step up close, you'll see all the cracks and flaws it has.
Because of this, I'm going to teach you the most recent version of C that I can make work with recent compilers. It'll be a practical, straightforward, simple, yet complete subset of C that works well, works everywhere, and avoids many pitfalls. This is the C that I use to get real work done, and not the encyclopedic version of C that hardcore fans try and fail to use.
I know the C that I use is solid because I spent two decades writing clean, solid C code that powered large operations without much failure at all. My C code has probably processed trillions of transactions because it powered the operations of companies like Twitter and AirBNB. It rarely failed or had security attacks against it. In the many years that my code powered the Ruby on Rails Web world, it's run beautifully and even prevented security attacks, while other Web servers fell repeatedly to the simplest of attacks.
My style of writing C code is solid, but more importantly, my mindset when writing C is one every programmer should have. I approach C, and any programming, with the idea of preventing errors as best I can and assuming that nothing will work right. Other programmers, even supposedly good C programmers, tend to write code and assume everything will work, but rely on UB or the operating system to save them, neither of which will work as a solution. Just remember that if people try to tell you that the code I teach in this book isn't "real C." If they don't have the same track record as me, maybe you can use what I teach you to show them why their code isn't very secure.
Does that mean my code is perfect? No, not at all. This is C code. Writing perfect C code is impossible, and in fact, writing perfect code in any language is impossible. That's half the fun and frustration of programming. I could take someone else's code and tear it apart, and someone could take my code and tear it apart. All code is flawed, but the difference is I try to assume my code is always flawed and then prevent the flaws. My gift to you, should you complete this book, is to teach you the defensive programming mindset that has served me well for two decades, and helped me make high-quality, robust software.
What You Will Learn
The purpose of this book is to get you strong enough in C that you'll be able to write your own software with it or modify someone else's C code. After this book, you should read The C Programming Language (Prentice Hall 1988) a book by the creators of the C language, also called K&R C. What I'll teach you is
- The basics of C syntax and idioms
- Compilation, make files, linkers
- Finding bugs and preventing them
- Defensive coding practices
- Breaking C code
- Writing basic UNIX systems software
By the final exercise, you will have more than enough ammunition to tackle basic systems software, libraries, and other smaller projects.
How to Read This Book
This book is intended for programmers who have learned at least one other programming language. I refer you to my book Learn Python the Hard Way, 5th Edition if you haven't learned a programming language yet. It's meant for beginners and works very well as a first book on programming. Once you've completed Learn Python the Hard Way, then you can come back and start this book.
For those who've already learned to code, this book may seem strange at first. It's not like other books where you read paragraph after paragraph of prose and then type in a bit of code here and there. Instead, there are videos of lectures for each exercise, you code right away, and then I explain what you just did. This works better because it's easier to explain something you've already done than to speak in an abstract sense about something you aren't familiar with at all.
Because of this structure, there are a few rules that you must follow in this book:
- Watch the lecture video first, unless the exercise says otherwise.
- Type in all of the code. Don't copy-paste!
- Type the code in exactly as it appears, even the comments.
- Get it to run and make sure it prints the same output.
- If there are bugs, fix them.
- Do the extra credit, but it's all right to skip anything you can't figure out.
- Always try to figure it out first before trying to get help.
If you follow these rules, do everything in the book, and still can't code C, then you at least tried. It's not for everyone, but just trying will make you a better programmer.
Included in this course are videos for every exercise, and in many cases, more than one video for an exercise. These videos should be considered essential to get the full impact of the book's educational method. The reason for this is that many of the problems with writing C code are interactive issues with failure, debugging, and commands. C requires much more interaction to get the code running and fix problems, unlike languages like Python and Ruby where code just runs. It's also much easier to show you a video lecture on a topic, such as pointers or memory management, where I can demonstrate how the machine is actually working.
I recommend that as you go through the course, you plan to watch the videos first, and then do the exercises unless directed to do otherwise. In some of the exercises, I use one video to present a problem, and then another to demonstrate the solution. In most of the other exercises, I use a video to present a lecture, then you do the exercise and complete it to learn the topic.
The Core Competencies
I'm going to guess that you have experience using a lesser language. One of those usable languages that lets you get away with sloppy thinking and half-baked hackery like Python or Ruby. Or, maybe you use a language like Lisp that pretends the computer is some purely functional fantasy land with padded walls for little babies. Maybe you've learned Prolog, and you think the entire world should just be a database where you walk around in it looking for clues. Even worse, I'm betting you've been using an integrated development environment (IDE), so your brain is riddled with memory holes, and you can't even type an entire function's name without hitting CTRL-SPACE after every three characters.
No matter what your background is, you could probably use some improvement in these four areas:
- Reading and Writing: This is especially true if you use an IDE, but generally I find programmers do too much skimming and have problems reading for comprehension. They'll just skim code that they need to understand in detail without taking the time to understand it. Other languages provide tools that let programmers avoid actually writing any code, so when faced with a language like C, they break down. The simplest thing to do is just understand that everyone has this problem, and you can fix it by forcing yourself to slow down and be meticulous about your reading and writing. At first, it'll feel painful and annoying, but take frequent breaks, and then eventually it'll be easier to do.
- Attention to Detail: Everyone is bad at this, and it's the biggest cause of bad software. Other languages let you get away with not paying attention, but C demands your full attention because it's right in the machine, and the machine is very picky. With C, there is no "kind of similar" or "close enough," so you need to pay attention. Double check your work. Assume everything you write is wrong until you prove it's right.
- Spotting Differences: A key problem that people used to other languages have is that their brains have been trained to spot differences in that language, not in C. When you compare code you've written to my exercise code, your eyes will jump right over characters you think don't matter or that aren't familiar. I'll be giving you strategies that force you to see your mistakes, but keep in mind that if your code is not exactly like the code in this book, it's wrong.
- Planning and Debugging: I love other, easier languages because I can just hang out. I can type the ideas I have into their interpreter and see results immediately. They're great for just hacking out ideas, but have you noticed that if you keep doing hack until it works, eventually nothing works? C is harder on you because it requires you to plan out what you want to create first. Sure, you can hack for a bit, but you have to get serious much earlier in C than in other languages. I'll be teaching you ways to plan out key parts of your program before you start coding, and this will likely make you a better programmer at the same time. Even just a little planning can smooth things out down the road.
Learning C makes you a better programmer because you are forced to deal with these issues earlier and more frequently. You can't be sloppy about what you write or nothing will work. The advantage of C is that it's a simple language that you can figure out on your own, which makes it a great language for learning about the machine and getting stronger in these core programming skills.
Register for Learn C the Hard Way
Register today for the course and get the all currently available videos and lessons, plus all future modules for no extra charge.