Vaihe 1: Esikääntäjän käsittely
Vaihe 2: Käännös kooditiedostosta objektitiedostoksi
Vaihe 3: Linkitys objektitiedostosta suoritettavaksi ohjelmaksi
Ohjelma voi muodostua useista tiedostoista, joille suoritetaan ensin erikseen vaiheet 1 ja 2. Lopuksi tiedostot linkitetään kokonaiseksi ohjelmaksi vaiheessa 3.
#-alkuisia komentoja, joita kutsutaan direktiiveiksi.
Tavallisia direktiivejä ovat #include,
joka lisää koodin osaksi toisen tiedoston,
sekä #define, joka määrittelee makron.
Olemme käyttäneet #include-direktiiviä aiemmin
standardikirjaston yhteydessä, jolloin tiedoston nimi annetaan
kulmasuluissa (kuten <iostream>).
Kun liitämme koodin osaksi oman tiedostomme, annamme puolestaan
tiedoston nimen lainausmerkeissä.
Seuraavassa esimerkissä tiedostossa koodi.cpp
on ohjelman koodi, jonka osaksi liitetään tiedostossa
lisa.inc oleva koodi.
// lisa.inc
cout << "Moikka!\n";
// koodi.cpp
#include <iostream>
using namespace std;
int main() {
#include "lisa.inc"
}
Tämä tarkoittaa samaa kuin seuraava koodi:
// koodi.cpp
#include <iostream>
using namespace std;
int main() {
// lisa.inc
cout << "Moikka!\n";
}
Direktiivi #define määrittelee makron,
joka tarkoittaa, että tietty merkkijono koodissa korvataan
toisella merkkijonolla. Esimerkiksi seuraava makro
korvaa merkkijonon pb merkkijonolla push_back.
#define pb push_backTämän makron seurauksena koodi
v.pb(1);muuttuu esikääntäjän käsittelyssä näin:
v.push_back(1);
koodi.cpp ja testi.cpp.
Tiedostossa testi.cpp on funktio testi,
jonka esittely on otsikkotiedostossa testi.h.
Ideana on, että koodi.cpp tietää otsikkotiedoston
ansiosta funktiosta testi, vaikka se ei näe funktion määrittelyä.
// testi.h void testi();
// testi.cpp
#include <iostream>
using namespace std;
void testi() {
cout << "Moikka!\n";
}
// koodi.cpp
#include <iostream>
#include "testi.h"
using namespace std;
int main() {
testi();
}
Ohjelman käännöksessä annetaan molemmat tiedostot
koodi.cpp ja testi.cpp:
$ g++ koodi.cpp testi.cpp -o koodiTiedostot voi kääntää myös erikseen näin:
$ g++ koodi.cpp -c $ g++ testi.cpp -c $ g++ koodi.o testi.o -o koodiTässä kaksi ensimmäistä riviä luovat käännetyt objektitiedostot
koodi.o ja testi.o
ja viimeinen rivi linkittää nämä tiedostot yhteen
suoritettavaksi ohjelmaksi.
main-funktion
määrittelyä, jossa on parametrit argc
(parametrien määrä)
ja argv (parametrit merkkitaulukkoina).
Esimerkiksi seuraava koodi tulostaa kaikki ohjelmalle annetut parametrit:
int main(int argc, char **argv) {
for (int i = 0; i < argc; i++) {
cout << i << " " << argv[i] << "\n";
}
}
Nyt voimme käynnistää ohjelman vaikkapa seuraavasti:
$ ./koodi apina banaani cembalo 0 ./koodi 1 apina 2 banaani 3 cembaloEnsimmäinen parametri on aina ohjelman nimi, eli
argc on aina vähintään 1,
ja tämän jälkeen tulevat mahdolliset muut parametrit,
jotka on erotettu välilyönneillä.
main-funktion tyyppi on int,
se voi palauttaa jonkin kokonaisluvun.
Jos main-funktiossa ei ole return-riviä,
se palauttaa oletuksena luvun 0,
jonka tavallinen tulkinta on, että ohjelma päättyi onnistuneesti.
Jos ohjelma kuitenkin palauttaa jotain muuta,
tämä tulkitaan virhetilanteeksi.
Esimerkiksi seuraava ohjelma palauttaa virheen merkkinä luvun 13:
int main() {
return 13;
}
Ohjelman suorituksen jälkeen voimme tarkastaa sen palautusarvon.
Esimerkiksi Linuxissa pääsemme käsiksi palautusarvoon
komentorivillä muuttujan $? kautta:
$ ./koodi $ echo $? 13Voisimme käyttää palautusarvoa esimerkiksi skriptissä, joka suorittaa ohjelman ja tarkastaa suorituksen jälkeen, päättyikö ohjelma onnistuneesti vai tapahtuiko jokin virhe.