Programe din mai multe fișiere (.c și .h) în C

Cum împarți un program C în fișiere sursă (.c) și antete (.h), cum le compilezi separat și cum le legi într-un executabil.

Sintaxă
// note.h – declarații
#ifndef NOTE_H
#define NOTE_H
double media(const int note[], int n);
#endif

// note.c – definiții
#include "note.h"
double media(const int note[], int n) { ... }

clang main.c note.c -o catalog

Ce face Programe din mai multe fișiere (.c și .h)

Un program mai mare se împarte în module. Fiecare modul are un antet (note.h) cu ce oferă celorlalte: prototipuri de funcții, tipuri (struct, typedef), constante și declarații extern. Implementarea stă în fișierul sursă cu același nume (note.c). Celelalte fișiere includ doar antetul, cu #include "note.h".

Fiecare fișier .c este compilat separat într-un fișier obiect (clang -c note.c → note.o). Apoi legătorul (linker-ul) combină obiectele într-un executabil și leagă fiecare apel de definiția funcției. Dacă o funcție este declarată, dar definiția ei lipsește din fișierele legate, eroarea apare la legare: „Undefined symbols” (macOS) sau „undefined reference” (Linux).

Funcțiile și variabilele care sunt folosite doar într-un fișier se declară static, ca să nu fie vizibile în altele. O variabilă globală comună se definește într-un singur .c și se declară cu extern în antet.

Exemple

Exemplul 1: Antet, implementare și program principal

main.c cunoaște funcția media din antet. Cele două fișiere sursă se dau împreună compilatorului, care le compilează și le leagă într-o singură comandă.

// note.h
#ifndef NOTE_H
#define NOTE_H

double media(const int note[], int n);

#endif

// note.c
#include "note.h"

double media(const int note[], int n) {
    int suma = 0;
    for (int i = 0; i < n; i++) {
        suma += note[i];
    }
    return (double)suma / n;
}

// main.c
#include <stdio.h>
#include "note.h"

int main(void) {
    int note[] = {9, 10, 8, 7};
    printf("Media Anei: %.2f\n", media(note, 4));
    return 0;
}

// în terminal:
// clang -std=c23 -Wall -Wextra main.c note.c -o catalog
// ./catalog

Ieșire în terminal

Media Anei: 8.50

Exemplul 2: Compilare separată și legare

-c produce câte un fișier obiect, fără legare. Ultima comandă primește doar obiectele și face executabilul. Așa lucrează și make: după o modificare în note.c, recompilează doar note.o.

# în terminal, în directorul cu note.h, note.c și main.c:
clang -std=c23 -Wall -c note.c
clang -std=c23 -Wall -c main.c
clang main.o note.o -o catalog
ls -1
./catalog

Ieșire în terminal

catalog
main.c
main.o
note.c
note.h
note.o
Media Anei: 8.50

Exemplul 3: Eroare la legare: lipsește un fișier

Compilarea lui main.c reușește, pentru că antetul declară media. Dar note.c nu a fost dat compilatorului, deci legătorul nu găsește definiția (pe macOS numele apare cu _ în față).

# în terminal:
clang -std=c23 main.c -o catalog

Ieșire în terminal

Undefined symbols for architecture arm64:
  "_media", referenced from:
      _main in main-728b8e.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Greșeli frecvente

  • Definești o variabilă globală în antet (int total = 0;). Fiecare .c care îl include creează propria variabilă, iar legarea dă „duplicate symbol”. În antet scrie extern int total;, iar definiția pune-o într-un singur .c.
  • Nu incluzi propriul antet în fișierul de implementare (note.c fără #include "note.h"). Dacă prototipul și definiția diferă, compilatorul nu are cum să observe.
  • Uiți garda de includere și antetul ajunge inclus de două ori, cu redefinirea tipurilor din el. Vezi #include.

Comenzi înrudite

  • #include: Copiază conținutul unui fișier antet (.h) în locul liniei, ca funcțiile și tipurile declarate acolo să poată fi folosite.
  • make și Makefile: make citește un Makefile și recompilează doar fișierele modificate, ca să nu scrii de fiecare dată comenzile de compilare.
  • Compilarea cu gcc și clang: Cum transformi codul C într-un program executabil cu gcc sau clang și ce fac opțiunile folosite cel mai des.
  • extern: Declară o variabilă globală definită în alt fișier (sau mai jos), ca să o poți folosi fără să creezi o copie nouă.
  • static: Într-o funcție, variabila își păstrează valoarea între apeluri; la nivel de fișier, ascunde funcția sau variabila de celelalte fișiere.
  • Funcții și prototipuri: Cum definești și declari funcții în C: tipul rezultatului, parametrii, prototipul și transmiterea argumentelor prin valoare.
Comunitate & Schimb de cunoștințe

Întrebări & Exemple de Cod: Programe din mai multe fișiere (.c și .h)

Ai o nelămurire despre utilizarea comenzii Programe din mai multe fișiere (.c și .h) sau ai descoperit un truc / fragment de cod util? Distribuie-l cu ceilalți programatori!

💬

Fii primul care pune o întrebare sau distribuie un fragment de cod / prompt!

Nu au fost adăugate încă întrebări sau exemple de cod pentru această pagină. Dacă ai întâlnit o problemă sau ai un snippet util, adaugă-l mai jos pentru a-i ajuta pe ceilalți.

Comunitate Adaugă o întrebare sau distribuie un cod

Moderare & Siguranță:

Pentru a menține calitatea și securitatea informațiilor, fiecare întrebare sau fragment de cod/prompt este analizat (manual sau prin moderare asistată de AI) înainte de publicare.