În acest curs vom explora bazele programării în limbajul C, începând cu arhitectura calculatorului și continuând cu structura unui program C.
Arhitectura unui calculator definește modul în care hardware-ul gestionează datele și instrucțiunile. Cele mai importante componente sunt:
- CPU (Unitatea Centrală de Procesare): Execută instrucțiunile programului și efectuează calcule.
- Memoria RAM: Păstrează datele temporare necesare pentru rularea programelor.
- Stocarea (SSD/HDD): Conține sistemul de operare și fișierele programelor.
- Perifericele (Tastatură, Monitor, Placă de rețea, etc.): Interfața cu utilizatorul și alte dispozitive.
În funcție de arhitectura hardware, un program trebuie compilat pentru platforma țintă. De exemplu, codul compilat pentru x86_64 nu poate rula direct pe un procesor ARM fără o recompilare.
Microprocesorul (CPU) este componenta principală care execută instrucțiunile programului. Caracteristicile sale influențează modul în care compilatorul generează codul binar.
- Arhitectura CPU (x86, ARM, RISC-V): Definirea setului de instrucțiuni pe care CPU-ul le poate executa.
- Modul de adresare a memoriei: Cum sunt accesate și gestionate datele în memorie.
- Niveluri de cache și optimizări: Compilatorul poate genera cod optimizat pentru performanță mai bună.
Compilarea este procesul prin care codul sursă este transformat în cod executabil. În C, acest proces se realizează în mai multe etape distincte.
source: https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
Compilatorul GCC (GNU Compiler Collection) realizează conversia codului C în fișier executabil prin patru etape majore:
Se expandează macro-urile (`#define`), se includ fișierele (`#include`) și se elimină comentariile. Rezultatul este un fișier `.i`.
gcc -E program.c -o program.i
Codul C este transformat în cod asembler, specific arhitecturii CPU. Rezultatul este un fișier `.s`.
gcc -S program.i -o program.s
Codul asamblator este transformat în cod mașină (binar) într-un fișier obiect `.o`.
gcc -c program.s -o program.o
Se combină fișierele obiect și se leagă bibliotecile pentru a obține fișierul executabil final.
gcc program.o -o program
Makefile ajută la gestionarea procesului de compilare, permițând recompilarea doar a fișierelor modificate.
program: program.c
gcc -o program program.c
Compilarea se realizează acum prin rularea comenzii:
make
Limbajul C suportă mai multe tipuri de date primitive și structurate:
- int: Numar întreg
- float: Număr real cu precizie simplă
- double: Număr real cu precizie dublă
- char: Caracter ASCII
- void: Tip fără valoare, folosit în funcții
#include <stdio.h>
int main() {
int a = 10;
float b = 5.5;
double c = 10.23456789;
char d = 'A';
printf("Int: %d, Float: %.2f, Double: %.8f, Char: %c\n", a, b, c, d);
return 0;
}
- Structuri (`struct`)
- Uniuni (`union`)
- Enumerări (`enum`)
- Pointeri (`*`)
Limbajul C include instrucțiuni de control al fluxului programului, cum ar fi condiționale și bucle.
Instrucțiunile `if-else` și `switch` sunt utilizate pentru a controla execuția unui program în funcție de condiții logice.
#include <stdio.h>
int main() {
int numar = 5;
if (numar > 0) {
printf("Numarul este pozitiv\n");
} else {
printf("Numarul nu este pozitiv\n");
}
return 0;
}
Instrucțiunea `switch` este utilizată pentru a gestiona multiple cazuri.
int main() {
int optiune = 2;
switch (optiune) {
case 1: printf("Ai ales 1\n"); break;
case 2: printf("Ai ales 2\n"); break;
default: printf("Opțiune invalidă\n");
}
return 0;
}
Buclele `for`, `while` și `do-while` sunt utilizate pentru a repeta execuția unor instrucțiuni.
int i;
for (i = 0; i < 5; i++) {
printf("Iteratia %d\n", i);
}
int i = 0;
while (i < 5) {
printf("Iteratia %d\n", i);
i++;
}
int i = 0;
do {
printf("Iteratia %d\n", i);
i++;
} while (i < 5);
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}