C előfordító
A C előfordító a C és C++ programozási nyelvek tényleges fordítása előtt végrehajtott speciális program. Az előfordító felel más forrásfájlok kezeléséért, felhasználható szimbólumok és makrók definiálására illetve a feltételes fordítás lehetővé tételéért. A hagyományos C programok erősen építenek rá, míg a C++-ban a típushelyesség miatt csak speciális esetekben használják.
Az előfordító feladatai
[szerkesztés]- Az ún. trigráf szekvenciák (??* alakú kifejezések, ??= → #, ??/ → \ stb.) lefordítása a nekik megfelelő karakterre.
- A forrásfájlban fizikailag több sorban elhelyezkedő forráskód logikailag egy sorba történő csoportosítása (ha szükséges).
- Preprocesszor tokenekre bontás, a kommentek helyettesítése whitespace karakterekkel.
- Az előfordítónak a programozó által megadott feladatok végrehajtása (szimbólumok behelyettesítése, feltételes fordítás, makrók, stb.).
Az előfordítónak szóló utasítások első sora a kettőskereszt (#, hashmark) karakterrel kezdődik és alapesetben a sor végén véget is ér, de a \ jellel semlegesíthetjük a sorvége jelet.
Fájlok beolvasztása
[szerkesztés]#include <iostream>
#include "otherfile.h"
A fenti két sor a nevezett fájlok tartalmát egyszerűen bemásolja az #include sor helyére. Az első esetben a forrásfájl nevét a kisebb-nagyobb (<, >) jelek közé írtuk, ezért a fordító a fejállományok szabványos helyén, a standard library-k között fogja keresni azt. A második példában idézőjelek közé helyeztük el a fájlnevet, így a jelenlegi fájl könyvtárából relatív útvonalon keresi azt a fordító.
Szimbólumok
[szerkesztés]Az ún. szimbólumtábla tartalmazza a forráskódban lévő és a fordítóban előre definiált szimbólumokat. Magunk is definiálhatunk saját szimbólumokat:
#define SAJAT_SZIMBOLUM
#ifdef SAJAT_SZIMBOLUM
std::cout << "SAJAT_SZIMBOLUM definiálva van!\n";
#else
std::cout << "SAJAT_SZIMBOLUM nincs definiálva!\n";
#endif
Ebben az esetben a define utasítással definiáltunk egy szimbólumot, a további részekben pedig megvizsgáljuk, hogy létezik-e. Ha igen, akkor a megfelelő programrész továbbadódik a fordítónak, ha nem, akkor az esetleges else rész kerül fordításra. A lehetséges utasítások:
#define: egy szimbólum definiálása és értékének megadása, utóbbi opcionális.#undef: egy szimbólum eltávolítása a szimbólumtáblázatból#ifdef: if define egy szimbólum létezését vizsgálja, csakendif-fel együtt használható.#ifndef: if not define egy szimbólum nemlétét ellenőrzi, csakendif-fel együtt használható.#else: az else lezárja a feltételt, majd az ellenkező esetnek kezd egy ágat.#endif: feltétel lezárása.
A szimbólumokhoz értéket is rendelhetünk, a fordító a forráskódban az azonosító összes előfordulási helyét lecseréli az értékére (ha nem adtunk meg, akkor semmire):
#define LENGTH 10
int * v = new int [LENGTH]; //10 elemű dinamikus tömb
Egyszerű szövegbehelyettesítést végez, ezért nem várt hatásai lehetnek, ha a tapasztalatlan programozó túl sok logikát feltételez róla.
A feltételekben használhatóak a defined és !defined predikátumok is.
#if !defined SAJAT_SZIMBOLUM //Ha SAJAT_SZIMBOLUM nincs definiálva
#define SAJAT_SZIMBOLUM
#endif
Makrók
[szerkesztés]#include <iostream>
#define MAX2(x, y) (x > y ? x : y) // 2 érték közül a nagyobbat adja vissza
int main(int argc, char * argv[])
{
std::cout << MAX2(10, 12) << std::endl;
return 0;
}
// MAX2(++x,x) meghatározhatatlan eredményhez vezetne
Definiáltuk a MAX2 makrót, amely a feltételes operátor segítségével a két érték közül a nagyobbikat adja vissza. Mivel a makró egy egyszerű szövegbehelyettesítés, bármely típusra meghívhatóak, fordítási és futásidejű hiba keletkezhet.
Makrók esetében használhatjuk a # és ## operátorokat. Előbbi a megadott paramétert adja vissza stringként, utóbbi összefűz két paramétert:
#define STR(x) #x // string
#define CONC(x, y) x ## y // concatenate
Őrszemek
[szerkesztés]Gyakran előfordul, hogy egy fejállomány áttételes include-ok hatására többször is bekerülne egy forrásfájlba, ami fordítási hibát okozna, bevett gyakorlat ennek kivédésére úgynevezett őrszemek (sentinel, header guard) használata:
// a "myheader.h" fájlban
#ifndef _MYHEADER_H_
#define _MYHEADER_H_
/*
Osztály-, függvénydefiníciók, stb.
*/
#endif
Amikor a fordító először találkozik a fejállománnyal megvizsgálja, hogy létezik-e már a szimbólum. Ha nem, akkor definiálja és beírja a szimbólumtáblázatba. Amikor legközelebb utasítást talál a fájl használatára, egyszerűen figyelmen kívül hagyja azt.
#line, #pragma, #error
[szerkesztés]A #line direktíva lehetővé teszi, hogy tetszőleges hibaüzenetet használjunk, ha fordítási hiba következik be:
#line 1 "bad operator"
a === b;
A #pragma segítségével utasításokat hagyhatunk a fordítónak. Nem minden fordító használja ugyanazokat a kapcsolókat, ezért ha ismeretlen utasítást tartalmaz, akkor a #pragma figyelmen kívül kerül.
Az #error megszakítja a fordítási folyamatot:
#ifndef SOMETHINGWHATNEED
#error "Something missing!"
#endif
Előre definiált szimbólumok
[szerkesztés]__LINE__: egész szám, annak a sornak a számát tartalmazza amiben szerepel.__FILE__: a forrásfájl nevét tartalmazza.__DATE__: a dátumot tartalmazza MMM:DD:YYYY formátumban.__TIME__: az időt tartalmazza HH:MM:SS formában.__cplusplus: egész érték. Ha a fordító teljes mértékben megfelel a szabványnak, akkor az értéke nagyobb vagy egyenlő mint 199711L az alkalmazott szabványtól függően.
Kapcsolódó hivatkozások
[szerkesztés]További információk
[szerkesztés]Források
[szerkesztés]- Brian Kernigham, Dennis Richie: A C programozási nyelv (ISBN 9789631605525, 2006)
- ISO/IEC 9899:TC2 szabványa