← Core SyntaxC PROGRAMMING 1.1.A

Setup & First Program

#include, main, printf format specifiers, escape characters, comments — the compilation pipeline end to end.

StatusCollected
NotesChapter test: 4/4

The five pieces of this chapter

This chapter broke into five pieces for me: the Hello World skeleton, the compilation pipeline hiding behind one gcc command, printf's format specifiers, escape characters, and the two comment styles. My first real writing exercise was printing a name, an age, and a float in a single printf call — %s, %d, and %f together instead of one at a time.

Hello, World

#include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
    return 0;
}
  • #include <stdio.h> — I'm not importing a library, I'm pulling in a header: declarations for printf and the rest of <stdio.h> that the compiler needs to see before it'll let me call them. The actual implementation gets linked in later, at the last pipeline stage.
  • int main(void) — the entry point. int is the return type; the shell reads it back as my process's exit code. (void) means explicitly no arguments — bare () in old-style C means "unspecified arguments," not "none," which caught me off guard the first time.
  • printf("Hello, World!\n") — a call into the C standard library, format string first, arguments after.
  • return 0; — exit code 0 conventionally means success to the shell (echo $? right after running it shows the number).

The compilation pipeline

gcc hello.c -o hello looks like one step. It's actually four, chained together silently:

StageToolInput → outputWhat happens
Preprocessingcpphello.c → hello.i#include files are pasted in literally, #define macros are textually substituted, comments are stripped.
Compilationcc1hello.i → hello.sPreprocessed C is translated into assembly for the target architecture.
Assemblyashello.s → hello.oAssembly becomes machine code, packaged as a relocatable object file.
Linkingldhello.o → helloThe object file is combined with the compiled C library — where printf actually lives — into one runnable executable.

I ran each stage on its own, just to stop treating the compiler as a black box:

gcc -E hello.c -o hello.i   # stop after preprocessing — read the expanded source
gcc -S hello.i -o hello.s   # stop after compilation — read the generated assembly
gcc -c hello.s -o hello.o   # stop after assembly — an object file, not yet runnable
gcc hello.o -o hello        # link — now it's runnable
Setting up

Before any of this I had to actually install the toolchain — sudo apt update && sudo apt install build-essential gdb valgrind git on Ubuntu/Debian/WSL, verified with gcc --version. build-essential is what actually provides gcc, as, and ld in the first place.

printf format specifiers

Eight specifiers, each telling printf how to read the next argument off the stack — get the specifier wrong and I get the wrong type back, silently:

SpecifierReads asExample
%dint, decimalprintf("%d", 42)42
%ccharprintf("%c", 'A')A
%ffloat / doubleprintf("%f", 3.14)3.140000
%schar*, stringprintf("%s", "hi")hi
%xunsigned int, hexprintf("%x", 255)ff
%ppointer, addressprintf("%p", &x)0x7ffee...
%uunsigned int, decimalprintf("%u", 42)42
%ldlong, decimalprintf("%ld", 100000L)100000
The one that kept catching me

%x prints hexadecimal, not decimal — printf("%x", 255) is ff, not 255. I got this one wrong more than once before it actually stuck — the kind of mistake worth actually drilling instead of just reading past it again.

Escape characters

EscapeMeaning
\nnewline
\ttab
\\a literal backslash
\"a literal double-quote inside a string
\0the null character — value 0, not the character '0'

\0 matters more to me than the other four combined: it's the terminator every C string relies on, the sentinel strlen scans for, and the one every hand-rolled string function I wrote later (1.3.F) had to respect explicitly. Here it was just a one-line mention; two topics later it became load-bearing.

Comments

// line comment — runs to end of line

/* block comment —
   can span
   multiple lines */

Both get stripped at the preprocessing stage above, before the compiler proper ever sees them — comments cost nothing at runtime, by construction.

Notes from readers

Comments — via GitHub