Ce face Compilarea cu gcc și clang
Un compilator C (gcc pe Linux, clang pe macOS, ambele pe Windows prin MSYS2 sau WSL) face patru pași: preprocesare (#include, #define), compilare în limbaj de asamblare, asamblare într-un fișier obiect (.o) și legare (linking) cu bibliotecile, rezultând executabilul. O singură comandă, clang program.c -o program, le face pe toate; -E, -S și -c te opresc după primul, al doilea sau al treilea pas.
Opțiuni de bază: -o nume (numele executabilului; fără ea se numește a.out), -std=c23 (standardul; fără ea, Clang 21 folosește C17 cu extensii GNU, iar GCC 15 folosește C23 cu extensii GNU), -Wall -Wextra (avertismente utile), -Wpedantic (avertismente pentru extensii nestandard), -Werror (avertismentele devin erori), -O0/-O2 (fără optimizare / optimizare obișnuită), -g (informații pentru debugger), -DNUME (definește o macro), -I dir (director pentru antete), -lm (leagă biblioteca matematică pe Linux).
Pentru căutarea greșelilor de memorie, -fsanitize=address (AddressSanitizer) și -fsanitize=undefined (UBSan) adaugă verificări la rulare: programul se oprește cu un raport exact când citește în afara unui tablou, folosește memorie eliberată sau face o depășire de int.
Parametri
| Parametru | Descriere |
|---|---|
-o program |
Numele fișierului executabil. |
-std=c23 |
Standardul limbajului: c89, c99, c11, c17, c23 (sau gnu23 cu extensii). |
-Wall -Wextra -Wpedantic |
Activează avertismentele recomandate. |
-Werror |
Orice avertisment oprește compilarea. |
-O0, -O2, -O3, -Os |
Nivelul de optimizare. |
-g |
Include informații pentru depanare (gdb, lldb). |
-c / -S / -E |
Se oprește după compilare (.o), după generarea codului de asamblare (.s) sau după preprocesare. |
-DNUME=val, -I dir, -l bib |
Definește o macro, adaugă un director de antete, leagă o bibliotecă (-lm). |
-fsanitize=address,undefined |
Verificări la rulare pentru erori de memorie și comportament nedefinit. |
Exemple
Exemplul 1: Compilare și rulare
Comanda compilează salut.c cu standardul C23 și avertismentele activate, apoi ./salut pornește programul. Dacă nu sunt erori, compilatorul nu afișează nimic.
// salut.c
#include <stdio.h>
int main(void) {
printf("Salut din Iași!\n");
return 0;
}
// în terminal:
// clang -std=c23 -Wall -Wextra -Wpedantic -O2 salut.c -o salut
// ./salut
Ieșire în terminal
Salut din Iași!
Exemplul 2: Avertisment, apoi eroare cu -Werror
Cu -Wall -Wextra, variabila nefolosită produce un avertisment, dar programul se construiește. Cu -Werror, același avertisment devine eroare și executabilul nu mai este creat.
// nota.c
#include <stdio.h>
int main(void) {
int nota = 9;
int neutilizat;
printf("Nota Anei: %d\n", nota);
return 0;
}
// în terminal:
// clang -std=c23 -Wall -Wextra nota.c -o nota
// clang -std=c23 -Wall -Wextra -Werror nota.c -o nota
Ieșire în terminal
nota.c:6:9: warning: unused variable 'neutilizat' [-Wunused-variable]
6 | int neutilizat;
| ^~~~~~~~~~
1 warning generated.
nota.c:6:9: error: unused variable 'neutilizat' [-Werror,-Wunused-variable]
6 | int neutilizat;
| ^~~~~~~~~~
1 error generated.
Exemplul 3: Un avertisment care previne o greșeală reală
%s așteaptă un șir, dar primește un int. La rulare, programul ar citi memorie de la o adresă greșită. Clang semnalează problema și propune %d.
// varsta.c
#include <stdio.h>
int main(void) {
int varsta = 20;
printf("Varsta: %s\n", varsta);
return 0;
}
// în terminal:
// clang -std=c23 -Wall varsta.c -o varsta
Ieșire în terminal
varsta.c:5:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
5 | printf("Varsta: %s\n", varsta);
| ~~ ^~~~~~
| %d
1 warning generated.
Greșeli frecvente
- Compilezi fără
-Wall -Wextra. Multe greșeli (specificatoriprintfgreșiți, variabile neinițializate, comparații întreintșiunsigned) apar doar ca avertismente, iar implicit unele sunt ascunse. - Uiți
-lmpe Linux când foloseștisqrtsaupowși primești „undefined reference to `sqrt’”. Pe macOS biblioteca matematică este legată automat. Pune-lmdupă fișierele sursă. - Rulezi programul cu
programîn loc de./program. Terminalul caută comenzile înPATH, nu în directorul curent. - Compari timpi de rulare compilând cu
-O0. Pentru măsurători folosește-O2;-O0este pentru depanare.
Comenzi înrudite
make și Makefile: make citește un Makefile și recompilează doar fișierele modificate, ca să nu scrii de fiecare dată comenzile de compilare.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.#define: Definește o macro: un nume pe care preprocesorul îl înlocuiește cu textul dat, înainte ca programul să fie compilat.#if, #ifdef, #ifndef: Compilare condiționată: preprocesorul păstrează sau elimină bucăți de cod în funcție de macro definite sau de valoarea lor.Comportament nedefinit (undefined behavior): Situațiile pentru care standardul C nu spune ce se întâmplă: programul poate merge, poate da rezultate greșite sau se poate opri.main: Funcția cu care începe orice program C: sistemul o apelează la pornire, iar valoarea returnată spune dacă programul a reușit.