← C ProgrammingC PROGRAMMING 1.1

Core Syntax

Hello-world through enums — the foundation chapters. Closed out with the topic final test.

What this topic covers

Core Syntax is the six chapters that got me from having gcc installed to being able to read driver source without flinching at every semicolon. It's the only topic in the whole thing with zero pointers, zero structs, zero malloc — just the language itself: how a program actually gets built, how values are typed, how control moves, how I name work into functions, and how a fixed set of named constants becomes an enum. Everything after this assumes it's automatic, not something I have to stop and think about.

The six chapters, in the order I went through them

  • A — Setup & First Program. Getting the compiler toolchain working, understanding what actually happens behind gcc hello.c -o hello, and enough of printf to get output out of a running program — the same reflex I now reach for reading dmesg.
  • B — Variables & Data Types. Every integer width from char to long long, unsigned wraparound, and the fixed-width types (uint8_t, uint32_t, ...) that hardware register maps actually specify — I stopped trusting int to mean any particular size.
  • C — Operators. Arithmetic, comparison, short-circuit logical operators, and the full bitwise set (& | ^ ~ << >>) — everything a register read-modify-write in a driver is built from.
  • D — Control Flow. if/switch/loops, and goto — which I'd always been told to avoid, until I saw it's the standard single-exit cleanup pattern the kernel uses for unwinding partial initialization.
  • E — Functions. Definitions, prototypes, static locals for state that persists between calls, and the pass-by-value rule that's the entire reason pointers exist — a function can't touch its caller's variables without one.
  • F — Enums. Named integer constants, and where I started noticing them everywhere in kernel code — enum irqreturn instead of raw magic numbers.
Things that tripped me up

Two things that tripped me up along the way: %x prints hexadecimal, not decimal — printf("%x", 255) prints ff, not 255. And integer division doesn't magically produce a decimal point just because I expect one — 5/2 prints 2, not 2.0, because the result type is decided by the operand types, not by whatever I do with the value afterward.

Where this lands in driver work

  • Bitwise operators (& | ^ ~ << >>) — this is directly how hardware registers get manipulated, bit by bit.
  • enum irqreturn — the return type every interrupt handler in the kernel uses.
  • goto — the kernel's standard cleanup-on-error-path pattern, and I'll be reaching for it constantly once I get to probe() functions.
  • static local variables — per-device state counters that survive across calls without turning into globals.
  • Fixed-width types (uint8_t, uint16_t, uint32_t) — guaranteed sizes for anything touching a hardware interface, where int just isn't good enough.

Notes from readers

Comments — via GitHub