Headers and multi-file projects
A header declares what a module offers; its .c file holds the one definition of each item. Every .c file is compiled on its own, and the linker joins the objects. Include guards stop a header being pasted twice, extern shares a variable, and static keeps the rest private.
Declaration or definition
A declaration tells the compiler that a name exists and what type it has: void led_set(int on); or extern int led_state;. A definition also creates it: the function body, or the variable's storage. A name can be declared many times but defined only once in the whole program. So the header, led.h, holds declarations, types and macros, and led.c holds the definitions.
#include <stdio.h>/* ---- led.h: the interface other files include ---- */#ifndef LED_H#define LED_Hvoid led_set(int on); /* declarations */int led_changes(void);extern int led_state;#endif/* ---- led.c: exactly one definition of each ---- */int led_state; /* definition */static int changes; /* private to led.c */void led_set(int on) { if (on != led_state) { changes++; } led_state = on;}int led_changes(void) { return changes;}/* ---- main.c: uses only what led.h declares ---- */int main(void) { led_set(1); led_set(1); led_set(0); printf("state %d, changes %d\n", led_state, led_changes()); return 0;}
state 0, changes 2
The example is shown as one file so that it compiles here; in a project, the three marked parts are led.h, led.c and main.c, and main.c starts with #include "led.h".
Guards, extern and static
The #ifndef LED_H / #define LED_H / #endif lines are an include guard: if a header is included twice, directly or through another header, the second copy is skipped. extern in the header lets other files use led_state, while static on changes keeps it private to led.c, so no other module can change it or clash with its name.