Kompilácia programu C: Zákulisie
Kompilácia je proces konverzie zdrojového kódu jazyka C na strojový kód. Keďže C je jazyk strednej úrovne, potrebuje kompilátor, ktorý ho prevedie na spustiteľný kód, aby bolo možné program spustiť na našom počítači.
Program C prechádza počas kompilácie nasledujúcimi fázami:
Proces kompilácie v C
Ako skompilujeme a spustíme program v C?
Najprv potrebujeme kompilátor a editor kódu na kompiláciu a spustenie programu C. Nižšie uvedený príklad je stroj Ubuntu s kompilátorom GCC.
Krok 1: Vytvorenie zdrojového súboru C
Najprv vytvoríme program v jazyku C pomocou editora a súbor uložíme ako názovsúboru.c
$ vi filename.c
Môžeme napísať jednoduchý program hello world a uložiť ho.
Krok 2: Kompilácia pomocou kompilátora GCC
Na kompiláciu nášho zdrojového súboru filename.c používame v termináli nasledujúci príkaz
$ gcc filename.c –o filename
Kompilátoru GCC môžeme odovzdať mnoho inštrukcií na rôzne úlohy, ako napríklad:
- Voľba -Wall povolí všetky varovné správy kompilátora. Táto možnosť sa odporúča na generovanie lepšieho kódu.
- Voľba -o sa používa na zadanie názvu výstupného súboru. Ak túto možnosť nevyužijeme, vygeneruje sa výstupný súbor s názvom a.out.
Ak v našom programe C nie sú žiadne chyby, vygeneruje sa spustiteľný súbor programu C.
Krok 3: Spustenie programu
Po vygenerovaní spustiteľného súboru kompilácie a vygenerovaný spustiteľný súbor spustíme pomocou nižšie uvedeného príkazu.
$ ./filename
Program sa vykoná a výstup sa zobrazí na termináli.
Čo je súčasťou procesu kompilácie?
Kompilátor konvertuje program C na spustiteľný súbor. Aby sa program C stal spustiteľným súborom, existujú štyri fázy:
- Prepojenie zostavy zostavy pred spracovaním
Vykonaním nižšie uvedeného príkazu získame všetky prechodné súbory v aktuálnom adresári spolu so spustiteľným súborom.
$gcc -Wall -save-temps filename.c –o filename
Nasledujúca snímka obrazovky zobrazuje všetky vygenerované prechodné súbory.
Medziľahlé súbory
Pozrime sa jeden po druhom, čo tieto prechodné súbory obsahujú.
1. Predspracovanie
Toto je prvá fáza, cez ktorú prechádza zdrojový kód. Táto fáza zahŕňa:
- Odstránenie komentárov
- Rozšírenie makier
- Rozšírenie zahrnutých súborov.
- Podmienená kompilácia
Predspracovaný výstup je uložený v názov súboru.i . Pozrime sa, čo je vo vnútri filename.i: using $vi názov súboru.i
Vo vyššie uvedenom výstupe je zdrojový súbor naplnený množstvom a množstvom informácií, ale nakoniec sa náš kód zachová.
- printf teraz obsahuje a + b namiesto add(a, b), pretože makrá sa rozšírili.
- Komentáre sú odstránené. Chýba #include, namiesto toho vidíme veľa kódu. Takže hlavičkové súbory boli rozšírené a zahrnuté do nášho zdrojového súboru.
2. Zostavovanie
Ďalším krokom je skompilovať súbor.i a vytvoriť súbor; prechodný kompilovaný výstupný súbor názov_súboru.s . Tento súbor je v pokynoch na úrovni zostavy. Pozrime sa na tento súbor pomocou $nano názovsúboru.s terminálový príkaz.
Súbor kódu zostavy
Snímka ukazuje, že je v jazyku symbolických inštancií, ktorému assembler rozumie.
3. Montáž
V tejto fáze je súbor.s braný ako vstup a premenený na názov_súboru.o zostavovateľom. Tento súbor obsahuje inštrukcie na úrovni stroja. V tejto fáze sa do strojového jazyka konvertuje iba existujúci kód a volania funkcií ako printf() nie sú vyriešené. Pozrime sa na tento súbor pomocou $vi názov súboru.o
Binárny kód
4. Prepojenie
Toto je posledná fáza, v ktorej sa vykoná všetko prepojenie volaní funkcií s ich definíciami. Linker vie, kde sú všetky tieto funkcie implementované. Linker tiež robí nejakú prácu navyše, pridáva do nášho programu nejaký extra kód, ktorý sa vyžaduje pri spustení a ukončení programu. Napríklad existuje kód, ktorý je potrebný na nastavenie prostredia, ako je odovzdávanie argumentov príkazového riadku. Túto úlohu možno ľahko overiť pomocou $veľkosť súboru.o a $veľkosť súboru . Prostredníctvom týchto príkazov vieme, ako sa výstupný súbor zväčší z objektového súboru na spustiteľný súbor. Je to kvôli dodatočnému kódu, ktorý Linker pridáva do nášho programu.
Poznámka: GCC v predvolenom nastavení vykonáva dynamické prepojenie, takže printf() je vo vyššie uvedenom programe dynamicky prepojené. Viac podrobností o statickom a dynamickom prepájaní nájdete v tomto, tomto a tomto.