Kutakin isompaa aliohjelmakokonaisuutta varten kirjoitetaan oma header- tiedosto (.h - tiedosto). Kääntäjän toiminta on sellainen, että kun kääntäjä tulee esimerkiksi lauseeseen
int a,i; ... a = ynnaa_yksi(i);
voidaan suluista päätellä aina, että kyseessä on aliohjelman kutsu. Loppu onkin kääntäjälle vaikeampaa. Aliohjelmalle pitäisi välittää oikean tyyppinen parametri. Kääntäjä voi yrittää arvata, että esimerkin aliohjelma olisi muotoa
int ynnaa_yksi(int luku);
koska sille välitetään parametrinä int - tyyppinen luku. Mikäli arvaus osoittautuisi vääräksi ja aliohjelma olisikin esitelty
double ynnaa_yksi(double luku);
olisi käännös mennyt väärin arvauksen kohdalta, koska kokonaisluku ja reaaliluku talletetaan aivan eri tavalla. Virhe voidaan normaalisti välttää sillä, että kirjoitetaan (esitellään) aliohjelma ennen sen käyttöä.
Aliohjelmakirjastojen kanssa on hankalampaa. Jottei aliohjelmia tarvitsisi esitellä useita kertoja, on aliohjelman parametrien tyypit mahdollista esitellä prototyypillä
int lue_jono(char *jono, int max_pituus);
Kun kaikkien tarvittavien aliohjelmien prototyypit laitetaan .h - tiedostoon, ja tämä tiedosto luetaan esiprosessorin
#include "mjonot.h"
direktiivillä käännöksen aikana koodin mukaan, saadaan kullekin aliohjelmalle oikea tyyppi.
Vastaavasti koko ohjelmaan saattaa tulla eri tiedostojen välisiä globaaleita muuttujia, ja kuitenkin muuttujan saa esitellä vain yhdessä paikassa. Jotta kaikki tiedostot näkisivät globaalit muuttujat, voidaan ne esitellä header- tiedostossa extern - määreellä. Itse varsinainen muuttuja varataan sitten siinä TASAN YHDESSÄ tiedostossa, johon se "eniten" kuuluu. Tällöin muuttujaan ei tule extern - määritystä.
kerho.h: extern const char *VERSIO; ... kerho.c const char *VERSIO = "18.2.1992" .. muissa tiedostoissa esimerkiksi: printf("Versio %s\n",VERSIO);
Siis yleensä header- tiedostoon tulee
Header- tiedostoon EI yleensä kirjoiteta varsinaisia kääntyviä lauseita, kuten muuttujien varaamista tai ohjelmakoodia (paitsi inline- funktioiden koodi)!