Intro

Perhaps one of the highest bars to entry to learning and becoming proficient with C is that the tooling, though actually being of very high quality, takes a while to get comfortable with. Though even a whole class would be unlikely to bestow confidence in the whole environment, I think this first session should begin by introducing the compiler.

The compiler

For this class, we will be using clang. Additionally, we will be moving forward under the asumption that the students all have access to a relatively new version though nothing we mention is likely to be specific to the latest version.

We will introduce three flags that we will be advising all students to use: -Weverything, -Werror and -std=c11.

  • -Weverything tells clang that it should generate a warning for every case where a warning can be generated. Many gcc users confuse -Wall to mean this when, in reality, -Wall actually generates relatively few warnings.
  • -Werror tells clang it should treat all warnings as errors (it should fail to compile). This forces the programmer to spend more time making sure the code pleases the compiler; and as a result, many programmers do not use it. However, in my experience, it almost universally leads to better code and should be applied universally, with the programmer explicitly disabling warnings which are erroneous, and only then after giving it significant thought.
  • -std=c11 tells clang that we wish it to only allow us to compile valid C11 code. This means we will be working of the latest standard and that clang will only allow us to use ISO C11 code.

More flags will be discussed later as we broach more significant topics (e.g., -fstack-protector-strong).

A Text Editor

We will not require students to use a specific text editor; however, we should encourage students to research which text editors are available and choose one they think works well for them. We should place some restrictions (e.g., it needs to be able to handle line-endings correctly (i.e., Microsoft Wordpad will not work)), but they will be general and still need to be worked out.

Honorable Mentions

There are, at least, two other tools we should mention to students, though I do not believe we will be introducing them in this session: valgrind and gdb (or lldb). We should say what they are for and offer students some reading on them to be done, perhaps, before the next class. A canned intro of segfaulting code and some light instructions of how to debug/fix it? (see jy2wong)

The First Project

Before the class is over, we should aim to have students have correctly compiled and run their own "Hello, World!" program. We should introduce the concepts line-by-line to construct the program.

System Message: ERROR/3 (<string>, line 44)

Error in "code-block" directive: unknown option: "linenos".

.. code-block:: c
    :linenos: true

    #include <stdio.h>                    // imports the standard IO library
    #include <stdlib.h>                   // imports the standard library

    signed main (void) {                  // the declaration of the main() function
        fputs("Hello, World!\n", stdout); // put string "Hello, World!" to stdout
        return EXIT_SUCCESS;              // indicate success in the program's exit status
    }

The above, even though it is actually not as simple as it could be (e.g., we will introduce puts() after this), is a valid C11 "Hello, World!" that introduces several important concepts and syntax and is mostly best-practice.

Makefiles

We will also be using make and Makefiles. Ideally, we would provide a very simple Makefile that provides the most basic setup possible while still being correct. It should include a rule to build the first project so that users can see how their first running of the compiler translates into a simple Makefile.

Types and Data Structures

Now that we have seen some of the basic syntax, we should start covering types.

We will try to cover all the scalar types, arrays and structs. cf. https://en.wikipedia.org/wiki/C_data_types

We will also cover implicit promotion, casting and unions.

The Second Project

This might be a good time to do a FizzBuzz implementation. We will need to introduce a couple more operators (% and ==) and a few control flow semantics for and if. But since this is not a class for programming beginners, it should be refresher for them.

System Message: ERROR/3 (<string>, line 80)

Error in "code-block" directive: unknown option: "linenos".

.. code-block:: c
    :linenos: true

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    #include <stdlib.h>

    signed
    main (void) {
        for ( uint8_t i = 1; i <= 100; ++ i ) {
            if      ( i % 15 == 0 ) { puts("fizzbuzz");          }
            else if ( i % 5  == 0 ) { puts("buzz");              }
            else if ( i % 3  == 0 ) { puts("fizz");              }
            else                    { printf("%" PRIu8 "\n", i); }
        } return EXIT_SUCCESS;
    }

Pointers

This class will begin by covering C's memory model, and introducing pointers. Ideally, we will be able to describe pointers in a fairly simple way (they are memory addresses represented by unsigned integers the same size as the word size on the machine).

In addition to introducing pointers, we will introduce the operators -> and .. We will also revisit [] and introduce * and define all four operators (which is pretty easy to do since they are all roughly identical). This lets us leverage a couple of the well-known fun examples of things like 2["abc"] being equal to 'c'.

cf. https://gist.github.com/jy2wong/22e621eec9d8fb553e6c

The Third Project

Given that we have introduced structs and arrays, we will cover exactly how strings work in C and should mess with them. Now seems like a good time to do some fun with IO. The typical IO introduction project is a guessing game.

System Message: ERROR/3 (<string>, line 116)

Error in "code-block" directive: unknown option: "linenos".

.. code-block:: c
    :linenos: true:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <stdint.h>
    #include <inttypes.h>

    signed
    main (void) {
        srand((unsigned )time(NULL));
        uint8_t u = 0, r = rand() % 100; // bad practice!

        while ( u != r ) {
            printf("Guess a number between 1 and 100: ");
            scanf("%" SCNu8, &u);
            const char * s = r > u ? "bigger" : "smaller";
            printf("You guessed %" PRIu8 ", the answer is %s\n", u, s);
        } puts("You got it!");

        return EXIT_SUCCESS;
    }

Undefined Behavior

Most C classes fail to adequately prepare people for one of---if not the---most annoying/tricky thing of C: undefined behavior.

This class should discuss it at length, offer examples of it, and give lots of useful resources and readings. It should also offer some examples of what the compiler can do to help the programmer (e.g., foreshadow clang 3.8's -fsanitize-trap=undefined)

For example:

The Fourth Project

TBD

Memory Management

We covered the Memory Model already in the pointers class, but we should also discuss actually working with memory management (namely with malloc() and free()).

The Fifth Project

TBD

Working with Libraries

We have already seen a few small libraries, let's introduce some others. I do not know yet what libraries we should introduce, because we still want them to be simple; perhaps jansson or libcurl (recommended since I know these two quite well)?

The Final Project

By this point, the projects will clearly have reached a point where they cannot be completed during the class, so this will need to be a culminating project to be completed by the student for their own enjoyment. TBD.