Master C

Your first C program

4 / 193
Contents

Contents

Master C

0 of 193 complete

10 min read

Compiling, and reading the errors

One command with four steps hiding inside it, and the four complaints you will meet in your first week.

So far a box on this page has done the building for you. On your own machine you do it yourself, with one command, and it is worth doing by hand at least once, because the parts of that command are the parts of the process.

Save the hello program from the last lesson as hello.c, open a terminal in the same folder, and run two commands. The first builds. The second runs what was built.

cc -std=c17 -Wall -Wextra -o hello hello.c
./hello
Build, then run. The second command only works if the first one said nothing.
  • cc is the C compiler. On most systems gcc and clang are also there and either will do; they disagree only about wording.
  • -std=c17 picks the version of the C standard to compile against. C has been revised several times and the default is not always the one you want, so say it.
  • -Wall -Wextra turn on warnings. Despite the name, -Wall is not all of them, which is why the second one is there too.
  • -o hello names the file to produce. Leave it out and you get a file called a.out, short for assembler output, a name that has outlived every reason for it.
  • hello.c is your source file, the text you wrote.
  • ./hello runs it. The ./ says the program is in this folder rather than somewhere on the system.

A compiler with nothing to say prints nothing. Silence is success, and the evidence is the new file sitting next to your source.

Four steps hiding in one command

That single command runs four programs one after another. You will not usually see the joins, but you will see error messages from two of them, and the messages read very differently.

From hello.c to a program that runsEach step hands its output to the next. A failure anywhere stops the lot.

Step 1 of 4. 1. Preprocess

hello.c  ->  one long file of plain C

Every #include is replaced by the text of that header, so the compiler proper never sees the word include at all.

The shape of a message

A compile error tells you the file, the line and the column, in that order, then the word error, then what it thinks is wrong. It usually quotes the offending line back at you with a caret under the exact spot.

hello.c:5:23: error: expected ';' at end of declaration
    5 |     int total = 10 + 5
      |                       ^
      |                       ;
One missing semicolon. gcc words it differently, but file, line and column come first either way.

Notice where the caret is pointing: the end of line 5, not line 6. The compiler read line 5, kept reading in the hope of a semicolon, found the start of another statement instead, and complained about the place where the semicolon should have been. Error positions point at where the compiler gave up, which is not always where you made the mistake.

Four you will meet in your first week

Each of the next four boxes is broken on purpose. Press play, read what comes back, then make the change the note suggests. Meeting a message deliberately is much cheaper than meeting it at midnight.

The first is the missing semicolon. It is the single commonest error in C and it is almost always reported on the line after the one you need to fix.

Try CodeC

Put a semicolon at the end of the first line and run it again.

The second is a name the compiler has never been introduced to. C insists that everything is declared before it is used, and it is case sensitive, so Total and total are two different names.

Try CodeC

Change total on the second line to subtotal and run it again. Then try Subtotal with a capital S and watch the same complaint come back.

The third is a quotation mark you never closed. This one is worth seeing because of how badly the message describes it: the compiler carries on reading your code as though it were text, and everything after the mistake confuses it.

Try CodeC

Put the closing quotation mark back, just before the closing bracket on the first line, and run it again. Count how many separate complaints one missing character produced.

The fourth comes from a different program entirely. Writing int square(int n); is a declaration: a promise that a function called square exists somewhere, taking one whole number and giving one back. The compiler takes you at your word. The linker, later, has to actually find it.

Try CodeC

Look for the word square in the message and notice there is no line number anywhere in it. Then delete the first line and run it again: the complaint changes completely, because now it is the compiler objecting rather than the linker.

That difference is worth holding on to. A message with a file and a line number came from the compiler and is about the text you wrote. A message about an undefined symbol or a missing reference came from the linker and is about a piece of code that was promised and never turned up. They are fixed in completely different ways, and later in this course, when your program is spread over several files, that distinction is most of the debugging.

Warnings are not errors

A warning means the compiler will build your program but thinks you have made a mistake. It is not a style complaint. Most of the C bugs that have ever cost anybody a weekend were a warning first.

hello.c:5:16: warning: format specifies type 'int' but the argument has type 'double' [-Wformat]
    5 |     printf("%d\n", 1.5);
      |             ~~     ^~~
A warning, with -Wall on. The program is still built and can still be run.

Here is what that one actually means. A value on its way to printf is not simply pushed into a queue: whole numbers and decimals are handed over in different places, and on a typical machine the 1.5 travels somewhere %d does not even look. So printf looks in the place a whole number would have been, finds whatever unrelated bytes happen to be sitting there, and prints those. The result is not 1 and it is not 2. It is meaningless: not rounded, not truncated, meaningless. The program builds, runs, prints something, and nobody is told. That is C in one example. The compiler noticed, mentioned it, and got out of the way.

The errors nobody can find for you

There are three ways a C program can be wrong and only two of them stop the build. It can fail to compile, which you have now seen four times. It can fail to link. Or it can build perfectly, run happily and produce the wrong answer, and that third one is the whole reason this course keeps talking about what is in memory.

Try CodeC

The compiler has no complaint at all, and the answer is wrong by 49p. Add a second %d to the text and pass total_pence % 100 as well, so the pence stop vanishing.

You run the build command and absolutely nothing is printed. Did it work?

Yes. A C compiler is silent when it has nothing to complain about, so no news is good news. Check by listing the folder: there should be a new file with the name you gave -o. If you are used to a tool that says Build succeeded, the silence feels like something went wrong; it is just the convention that a program prints only when it has something to say.

All lessons in Master C