next up previous contents
Elõre: Megjegyzések Fel: Az elõfeldolgozó Vissza: Az elõfeldolgozó

Szimbólumok és makrók

Az elõfeldolgozónak szintén lehetnek "változói", ezeket szimbólumoknak, illetve makróknak nevezzük, és ugyanaz a képzési szabály vonatkozik rájuk, mint más azonosítókra. Azért, hogy a preprocesszor számára definiált szimbólumok a C forrásnyelvi szövegben élesen különváljanak a programban használt azonosítóktól, szokás szerint a szimbólumokat csupa nagybetûvel képezzük. Szimbólumokat a következõ parancssal hozhatunk létre:

      #define   szimbólum   helyettesítendõ szöveg

A három fõ részt tetszõleges számú, min. 1 db. szóköz és/vagy tabulátor választja el. Az elõfeldolgozó minden beérkezõ sort átvizsgál, tartalmaz-e korábban definiált szimbólumot. Ha igen, akkor azt lecseréli a megfelelõ helyettesítõ karaktersorozatra, és újból átvizsgálja a sort szimbólumokat keresve, amit új helyettesítés követhet, stb. Mindaddig folytatódik ez a folyamat, amíg vagy nem talál a sorban szimbólumot, vagy csak olyat talál, ami már egyszer helyettesítve lett (a végtelen rekurziók elkerülésére). Példák szimbólumdefinícióra: |

           #define   EOS       '\0'
           #define   TRUE      1
           #define   FALSE     0
           #define   YES       TRUE
           #define   bool      int
           #define   MENUCOL   20
           #define   MENULINE  5
           #define   BORDER    2
           #define   MENUROW   (MENULINE+BORDER)
Az elsõ három példában szereplõ szimbólumokra szinte minden C programban szükség van. Figyeljük meg, hogy a YES-t a TRUE segítségével definiáltuk, ami kettõs helyettesítéssel válik majd 1-gyé. A következõkben egy lehetõséget mutatunk arra, hogyan lehet a C nyelv alapszavait kibõvíteni: bár explicit logikai típus a nyelvben nem létezik, mi létrehozhatunk egy új "alapszót", a bool-t, amit azután természetesen éppúgy használhatunk, mint az eredeti int-et (hiszen úgyis arra cserélõdik le), de használatával az egyes változók szerepét jobban kidomboríthatjuk. Az alapszó jelleg hangsúlyozása érdekében használtunk ennél a szimbólumnál kisbetûket. A további definíciók a szimbólumok leggyakrabban használt területét mutatják be: legfõbb hasznuk az, hogy a különbözõ "bûvkonstansokat" névvel ellátva egy helyre gyûjthetjük össze, világosabbá téve használatukat és megkönnyítve módosításukat. Az utolsó példát annak illusztrálására hoztuk fel, hogy milyen fontos szem elõtt tartani azt, hogy szöveghelyettesítésrõl van szó. Ha a látszólag felesleges zárójelpárt elhagynánk, akkor a következõ sorból
           #define   MENUSIZE  (MENUROW*MENUCOL)
az alábbi keletkezne
           #define   MENUSIZE  (MENULINE+BORDER * MENUCOL)
ami végeredményben a kívánt 140 helyett 45-öt eredményezne mindenütt, ahol MENUSIZE-t használjuk. Mivel a felesleges zárójelek bajt nem okozhatnak, szokjuk meg, hogy minden definícióban szereplõ kifejezést zárójelezünk.

A makrók lehetõvé teszik azt, hogy a szöveghelyettesítés paraméterezhetõ legyen. A paraméterek számára nincs elvi korlát megadva. Példák makródefinícióra:

           #define   abs(x)    ((x) < 0 ? (-(x)) : (x))
           #define   min(a, b) ((a) < (b) ? (a) : (b))
(Az itt szereplõ, ún. feltételes kifejezéseket a megfelelõ helyen tárgyalni fogjuk. Ha a ? elõtt álló kifejezés logikai értéke igaz, akkor a ? és a : között álló, egyébként a : után álló kifejezés szolgáltatja az eredményt.) Figyeljük meg, hogy - szintén a szöveghelyettesítést szem elõtt tartva - makrók esetében nemcsak a helyettesítõ kifejezést, de a helyettesítendõ paramétereket is zárójelekkel védjük. Az elsõ példában szereplõ makró alábbi alakú hívása
           alfa = abs(y + 2);
így a következõ sort eredményezi
           alfa = ((y + 2) < 0 ? (-(y + 2)) : (y + 2));
Ha y értéke -3, akkor alfa-ba 1 kerül, mint az várható. Ha azonban a definíció helyettesítõ részében az x-et védõ zárójeleket elhagytuk volna, akkor alfa 5-öt kapna értékül. Itt hívjuk fel a figyelmet arra is, hogy alfa kiszámításához a fenti esetben az y+2 értékét kétszer kell meghatározni. Egyszer a feltétel kiértékelésekor, aztán az eredmény meghatározásához. Ez komplikáltabb kifejezés esetében a program hatékonyságát jelentõsen ronthatja. Nagyobb bajt okoz azonban az, hogy a C-ben bizonyos kifejezéseknek ún. mellékhatásuk is lehet (például a kifejezés tartalmazhatja olyan függvény meghívását, ami a kívánt érték kiszámítása mellett, azt ki is írja a képernyõre), és a többszöri kiértékelés a mellékhatás többszöri jelentkezését vonja maga után (példánknál a részeredmény kétszer kerül kiírásra). Az ilyen makrók használatánál ezért célszerûbb az adott kifejezést egy ideiglenes változóba helyezni, és azzal meghívni a makrót. A makrók használatának szintaxisa, mint majd látni fogjuk, megegyezik a függvények hívásának szintaxisával. Ez nem véletlen, ugyanis több könyvtári "függvényt" például sok C rendszer makróként valósít meg (ilyen "függvény" a pelda.c-ben használt getchar() is), ami a használatát nem befolyásolja - a fent említett ritka kivételektõl eltekintve, mint például toupper(), tolower(), min(), max(), stb. - ugyanakkor a rutinhívások elmaradása miatt gyorsabb kódot eredményez. Felhasználhatók a makrók arra is, hogy a program egy új telepítésénél az adott rendszerben esetleg eltérõ nevû, vagy paraméterezésû könyvtári függvényeket segítségükkel a korábbi alakban használhassuk.

Ha egy szimbólum vagy makró által lefoglalt azonosítót fel szeretnénk szabadítani, azt az

             #undef   szimbólum

utasítással tehetjük meg. Ezt követõen az elõfeldolgozó a szimbólum (makró) további elõfordulásait nem kíséri figyelemmel. Természetesen egy újabb #define utasítással újradefiniálhatjuk ezt a szimbólumot is.
 



next up previous contents
Elõre: Megjegyzések Fel: Az elõfeldolgozó Vissza: Az elõfeldolgozó