Ce face extern
Un program C este format de obicei din mai multe fișiere .c, compilate separat și apoi legate. Dacă o variabilă globală este definită într-un fișier și vrei să o folosești în altul, scrii în al doilea extern int contor;. Aceasta este doar o declarație: nu alocă memorie și nu inițializează, ci spune „există undeva o variabilă cu acest nume și tip”.
Regula practică: definiția (int contor = 0;) stă într-un singur fișier .c, iar declarația extern stă în fișierul .h inclus de toți cei care o folosesc. Dacă două fișiere definesc aceeași variabilă, linkerul dă eroare de simbol duplicat.
La funcții, extern este implicit: un prototip void f(void); are deja legătură externă. Opusul lui extern este static la nivel de fișier, care ascunde numele de celelalte fișiere.
Exemple
Exemplul 1: Declarație extern înainte de definiție
Într-un singur fișier: extern permite folosirea variabilei înainte de linia unde este definită. Definiția de la final alocă memoria și o inițializează.
#include <stdio.h>
extern int vizitatori; // declarație
void inregistreaza(void) {
vizitatori++;
}
int main(void) {
inregistreaza();
inregistreaza();
printf("Vizitatori: %d\n", vizitatori);
return 0;
}
int vizitatori = 100; // definiție
Rezultat
Vizitatori: 102
Exemplul 2: O variabilă comună în trei fișiere
config.h declară variabila, config.c o definește, iar main.c o folosește. Se compilează împreună: cc main.c config.c -o magazin.
// config.h
#ifndef CONFIG_H
#define CONFIG_H
extern double cota_tva;
extern const char *oras_magazin;
#endif
// config.c
#include "config.h"
double cota_tva = 0.21;
const char *oras_magazin = "Iași";
// main.c
#include <stdio.h>
#include "config.h"
int main(void) {
printf("Magazin: %s, TVA %.0f%%\n", oras_magazin, cota_tva * 100);
return 0;
}
Ieșire în terminal
$ cc -std=c23 -Wall main.c config.c -o magazin
$ ./magazin
Magazin: Iași, TVA 21%
Exemplul 3: Ce se întâmplă cu definiție dublă
Dacă pui în config.h definițiile (cu valoare, fără extern) și îl incluzi din main.c și config.c, fiecare fișier are propria definiție, iar linkerul refuză programul. Mesajul de mai jos este cel dat de linkerul de pe macOS; pe Linux, ld scrie „multiple definition of `cota_tva’”.
// config.h – GREȘIT: definiții în fișierul header
double cota_tva = 0.21;
const char *oras_magazin = "Iași";
Ieșire în terminal
$ cc -std=c23 main.c config.c -o magazin
duplicate symbol '_cota_tva' in:
/private/var/folders/y_/5jgx6vgd5r3_4fq2thfw7cl40000gn/T/config-3a0d94.o
/private/var/folders/y_/5jgx6vgd5r3_4fq2thfw7cl40000gn/T/main-3cb1b1.o
duplicate symbol '_oras_magazin' in:
/private/var/folders/y_/5jgx6vgd5r3_4fq2thfw7cl40000gn/T/config-3a0d94.o
/private/var/folders/y_/5jgx6vgd5r3_4fq2thfw7cl40000gn/T/main-3cb1b1.o
ld: 2 duplicate symbols
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Greșeli frecvente
- Pui definiția variabilei (cu valoare) în fișierul
.h. Fiecare.ccare îl include primește o definiție; linkerul dă „duplicate symbol”. În.hpune doarextern. - Scrii
extern int x = 5;și te aștepți să fie doar o declarație. Cu inițializare, devine definiție (iar compilatorul avertizează). - Declari
extern int note[];într-un fișier și defineștiint *note;în altul. Tipurile trebuie să fie identice: un tablou nu este același lucru cu un pointer.
Comenzi înrudite
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.Programe din mai multe fișiere (.c și .h): 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.#include: Copiază conținutul unui fișier antet (.h) în locul liniei, ca funcțiile și tipurile declarate acolo să poată fi folosite.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.