The Holy RGWY.ORG Bible: The Book of C

Table of Contents

  1. Who this is for
  2. About C
  3. Setup
    1. Compiler
    2. Linker
    3. Project Layout
  4. Hello, world!
  5. Prerequisites
    1. What is memory?
    2. Why numbers matter

Who this is for

This is a detailed guide for any curious person that is interested in learning a bit about C and the inner workings of computers. You do not have to have any prior programming experience to use this guide, however a good understandig of math and basic computer concepts will come in very handy. Also, many topics (especially later throughout the guide) can turn pretty advanced very quickly, so I personally recommend properly internalizing all concepts explained up to those points prior to learning the next concept. Also, I highly recommend you to not read this entire bible in a single day, because one can only remember so many things in a certain time frame and by the time you have reached the end, you will most likely have already forgotten 80% of the parts before.

Another thing I would definetly advise you to do is not to focus too much on the theoretical part of the language, but actually coming up with personal projects yourself, putting into practice all that you have learned up to that point. This way, you do not risk getting bored quickly and you develope intuition for the language, which is absolutely crucial if you wish to become an expert eventually.


About C

C is a programming language which has existed since the 1970s and has seen widespread use in embedded and systems programming. It is still widely used in academics as well as open source projects, and serves as the de-facto standard for most Operating System API interfaces.

The features of the C language have evolved over time. There are several standards which define what constitutes a C program and how it ought to behave. These standards are categorized by the year they have been published, and are as follows:

There are also noteworthy compiler-specific extensions to the language, such as GNU C or Microsoft C (MSVC). Many of those extensions have been merged back into other compilers and have become de-facto standards.

But before I start throwing around too much terminology here, I want to take a step back again and refer to the original guiding question: What is C? C is, as I have demonstarated above, not a single language, but rather a collection of many different dialects which share a common denominator. I will try to quickly outline what this common denominator is and what makes C, or the collection of dialects that are covered by this term, distinct from other languages that are commonly used today, such as Python.

  1. C permits direct access to memory. To understand what this means, you first have to grasp that Objects as they appear in other languages are really just smokes and mirrors which are supposed to make life easier for you by hiding the inner workings and the attached complexity away from you. Take a string, for example (or a bunch of text in layman terms). Your computer has not the faintest idea what text is. All it knows and all it can ever be tought, as per design, is 1s and 0s. Everything the computer understands has to come in the form of numbers. Because I will go into more detail about this later on, I will simplify it here by just saying that the computer just stores multiple numbers in sequence which represent the alphabetical positions of the actual characters in the text, even though this is not entirely accurate. What makes C distinct from other languages in this point is that C is able to directly change or read any numbers that together make up an Object, whereas Python for example only permits changes or reads to the Object through its own defined set of operations.
  2. C requires manual memory management. This expands upon the previous point, but is not exactly the same concept. In most (if not all) programming languages in use today, variables have so-called lifetimes. This means, a variable can only be used after it has been defined and only until it is destroyed, for example when a function exits. Now, if you remember the previous point, you know that all variables on a fundamental level only consist of a certain set of numbers. These numbers have to be stored somewhere in order to be reused. Multiple problems arise, for example, how does the program itself know when those numbers are no longer needed, and multiple solutions have been developed over time. Python and Java, for example, among many others have adopted the concept of a "garbage collector", a tiny part of the program running in the background which keeps track of how many variables contain a certain object. Rust, a fairly popular language as of recently, has invented its own unique concept of a "borrow checker", which imposes certain rules upon the program during compilation (translation from the human-readable source code into machine-readable binary code) to guarantee that a variable does not exceeds its lifetime. C on the other hand delegates most of the responsiblity for requesting memory and giving it back to the developer. This has both costs and advantages. While it is easier to make mistakes this way and a lot of weird, potentially dangerous bugs can occure if the developer is too careless, it allows for a great degree of control and has many opportunities for optimizations by the developer due to in-depth knowledge about what data is needed when that can hardly be matched by automatized analysis.
  3. C is statically, explicitly typed. In programming, every variable is of a specific type. I already mentioned strings and numbers, but there are many others, for example lists, dictionaries or booleans, just to name a few. These data types determine what operations can be performed on the data and what information is contained within a variable. Pythons type system works opposite to that of C: variables are dynamic instead of static, meaning they can change their type throughout the program. In C, variables have one definitive type that never changes. Variables in Python are also implicitly typed, meaning the type is inferred from the value that is assigned to the variable, whereas in C every variable has a type that must be explictily given to the variable, and assigning the variable automatically converts the value to match the explictly specified type. Although having explicitly typed variables might appear quite tedious at first, it makes spotting errors much easier.
  4. C is not Object Oriented. Most popular modern programming languages rely to some degree on Object Oriented Programming (OOP). The term "Object Oriented" is very loosely defined, but terms commonly associated with it are Classes, Polymorphism, Generics, Inheritance, Constructors and Methods, and probably a lot more. Some of these also describe C features, or at least have analogous concepts. Despite that, C is not considered an OOP language, because most importantly Classes and Inheritance are not supported. While many people would probably argue that this is a weakness of C, I myself believe that it makes programming much more straightforward, because the emphasis in C lies on the control flow of the program, or the logic if you will, rather than an artificially imposed concept of how Objects interact with each other, which is not as beneficial in practice as commonly claimed in theory. Because in truth, Objects do not interact with Objects, but rather Code interacts with Objects, so the Objects might as well just be data and not try to be anything else. There is a great video by Brian Will if you want to learn more about what good arguments there are against OOP: Link to video