Amint a neve is mutatja, a preprocesszorok olyan programok, amelyek a fordítás előtt feldolgozzák a forráskódunkat. A program megírása és a program végrehajtása között számos lépés van C / C++ nyelven. Nézzük meg ezeket a lépéseket, mielőtt ténylegesen elkezdenénk tanulni a preprocesszorokról.

A fenti ábrán láthatjuk a köztes lépéseket. A programozók által írt forráskódot a program.c fájlban tároljuk, majd ezt a fájlt a preprocesszorok feldolgozzák, és egy kibővített forráskódfájlt generálnak program néven. Ezt a kibővített fájlt a fordítóprogram lefordítja, és egy program .obj nevű objektumkód-fájlt hoz létre. Végül a linkelő összekapcsolja ezt az objektumkódfájlt a könyvtári függvények objektumkódjával, hogy létrehozza a program.exe futtatható fájlt.

A preprocesszor programok preprocesszor direktívákat adnak meg, amelyek megmondják a fordítónak, hogy a forráskódot a fordítás előtt előfeldolgozza. Ezek a preprocesszor direktívák mindegyike egy ‘#’ (hash) szimbólummal kezdődik. A ‘#’ szimbólum azt jelzi, hogy bármilyen utasítás #-sel kezdődik, az a preprocesszor programhoz kerül, és a preprocesszor program végre fogja hajtani ezt az utasítást. Példák néhány preprocesszor direktívára: #include, #define, #ifndef stb. Ne feledje, hogy a # szimbólum csak egy utat ad meg, hogy a preprocesszorhoz fog menni, és az olyan parancsokat, mint az include, a preprocesszor program dolgozza fel. Például az include extra kódot fog beépíteni a programodba. Ezeket a preprocesszor direktívákat bárhol elhelyezhetjük a programunkban.

A preprocesszor direktíváknak 4 fő típusa van:

  1. Makrók
  2. File Inclusion
  3. Conditional Compilation
  4. Egyéb direktívák

Most ismerjük meg részletesen az egyes direktívákat.

  • Makrók: A makrók olyan kódrészletek a programban, amelyeknek valamilyen nevet adunk. Amikor a fordító ezzel a névvel találkozik, a fordító a nevet a tényleges kódrészlettel helyettesíti. A ‘#define’ utasítás egy makró definiálására szolgál. Értelmezzük most a makródefiníciót egy program segítségével:
C++

#include <iostream>
#define LIMIT 5
int main()
{
for (int i = 0; i < LIMIT; i++) {
std::cout << i << "\n";
}
return 0;
}



C

#include <stdio.h>
#define LIMIT 5
int main()
{
for (int i = 0; i < LIMIT; i++) {
printf("%d \n",i);
}
return 0;
}



Kimenet:

01234

A fenti programban, amikor a fordító a LIMIT szót végrehajtja, azt 5-re cseréli. A ‘LIMIT’ szót a makródefinícióban makrósablonnak nevezzük, az ‘5’ pedig makróbővítésnek.

Megjegyzés: A makródefiníció végén nincs pontosvessző(‘;’). A makródefinícióknak nincs szükségük pontosvesszőre a befejezéshez.

Makrók argumentumokkal: A makróknak érveket is átadhatunk. Az argumentumokkal definiált makrók hasonlóan működnek, mint a függvények. Értelmezzük ezt egy program segítségével:

C++

#include <iostream>
#define AREA(l, b) (l * b)
int main()
{
int l1 = 10, l2 = 5, area;
area = AREA(l1, l2);
std::cout << "Area of rectangle is: " << area;
return 0;
}



C

#include <stdio.h>
#define AREA(l, b) (l * b)
int main()
{
int l1 = 10, l2 = 5, area;
area = AREA(l1, l2);
printf("Area of rectangle is: %d", area);
return 0;
}



Kimenet:

Area of rectangle is: 50

A fenti programból láthatjuk, hogy amikor a fordító a programban AREA(l, b)-t talál, azt a (l*b) utasítással helyettesíti. Nem csak ez, hanem az AREA(l, b) makrósablonhoz átadott értékek is az (l*b) utasítással lesznek helyettesítve. Ezért az AREA(10, 5) egyenlő lesz a 10*5-tel.

  • Fájlbővítés: Ez a típusú előfeldolgozói utasítás azt mondja a fordítónak, hogy egy fájlt építsen be a forráskódú programba. Kétféle fájltípust lehet a felhasználó által a programba bevonni:
    • Fejlécfájl vagy szabványos fájlok: Ezek az állományok olyan előre definiált függvények definícióját tartalmazzák, mint a printf(), scanf() stb. Ezeket a fájlokat be kell építeni a függvényekkel való munkához. A különböző függvények különböző fejlécfájlokban vannak deklarálva. Például a szabványos I/O funkciók az ‘iostream’ fájlban vannak, míg a string műveleteket végző funkciók a ‘string’ fájlban.
      Szintaktika:
#include< file_name >

ahol a file_name a beépítendő fájl neve. A ‘<‘ és ‘>’ zárójelek azt mondják a fordítónak, hogy a fájlt a standard könyvtárban keresse.

  • felhasználó által definiált fájlok: Amikor egy program nagyon nagy lesz, jó gyakorlat, ha kisebb fájlokra osztjuk fel, és akkor csatoljuk be, amikor csak szükséges. Az ilyen típusú fájlok a felhasználó által definiált fájlok. Ezeket a fájlokat úgy lehet bevonni, mint:
#include"filename"
  • Feltételes fordítás: A feltételes fordítási direktívák olyan típusú direktívák, amelyek segítenek a program egy adott részének lefordításában, vagy a program egy adott részének fordításának kihagyásában bizonyos feltételek alapján. Ezt két előfeldolgozási parancs, az ‘ifdef’ és az ‘endif’ segítségével lehet megtenni.
    Szintaktika:
#ifdef macro_name statement1; statement2; statement3; . . . statementN;#endif

Ha a ‘macroname’ nevű makró definiálva van, akkor az utasításblokk normálisan végrehajtódik, de ha nincs definiálva, akkor a fordító egyszerűen kihagyja ezt az utasításblokkot.

  • Egyéb direktívák: A fenti direktívákon kívül van még két másik direktíva, amelyeket nem gyakran használnak. Ezek a következők:
    • #undef irányelv: A #undef direktívát egy meglévő makró undefiniálására használjuk. Ez a direktíva a következőképpen működik:
#undef LIMIT

Ezzel az utasítással a meglévő LIMIT makrót vonjuk vissza. Ezt az utasítást követően minden “#ifdef LIMIT” utasítás értéke hamis lesz.

  • #pragma irányelv: Ez az utasítás egy speciális célú utasítás, és bizonyos funkciók be- vagy kikapcsolására szolgál. Az ilyen típusú direktívák fordítóspecifikusak, azaz fordítóról fordítóra változnak. Az alábbiakban néhány #pragma direktívát tárgyalunk:
    • #pragma startup és #pragma exit: Ezek a direktívák segítenek megadni azokat a függvényeket, amelyeket a program indítása előtt( mielőtt a vezérlés átkerül a main() parancsra) és közvetlenül a program kilépése előtt (közvetlenül azelőtt, hogy a vezérlés visszatér a main() parancsból) kell futtatni.
      Figyelem: Az alábbi program nem fog működni a GCC fordítóval.
      Nézzük meg az alábbi programot:
C++

#include <bits/stdc++.h>
using namespace std;
void func1();
void func2();
#pragma startup func1
#pragma exit func2
void func1()
{
cout << "Inside func1()\n";
}
void func2()
{
cout << "Inside func2()\n";
}
int main()
{
void func1();
void func2();
cout << "Inside main()\n";
return 0;
}



C

#include <stdio.h>
void func1();
void func2();
#pragma startup func1
#pragma exit func2
void func1()
{
printf("Inside func1()\n");
}
void func2()
{
printf("Inside func2()\n");
}
int main()
{
void func1();
void func2();
printf("Inside main()\n");
return 0;
}



Kimenet:

Inside func1()Inside main()Inside func2()

A fenti kód a GCC fordítóprogramon futtatva az alábbi kimenetet fogja eredményezni:

Inside main()

Ez azért történik, mert a GCC nem támogatja a #pragma indítást vagy kilépést. Az alábbi kódot azonban használhatja a GCC fordítóprogramokon hasonló kimenethez.

C

#include <stdio.h>
void func1();
void func2();
void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();
void func1()
{
printf("Inside func1()\n");
}
void func2()
{
printf("Inside func2()\n");
}
int main()
{
printf("Inside main()\n");
return 0;
}



  • #pragma warn irányelv: Ez a direktíva a fordítás során megjelenő figyelmeztető üzenetek elrejtésére szolgál.
    A figyelmeztetéseket az alábbiak szerint rejthetjük el:
    • #pragma warn -rvl: Ez az utasítás elrejti azokat a figyelmeztetéseket, amelyek akkor jelennek meg, ha egy olyan függvény, amelynek értéket kellene visszaadnia, nem ad vissza értéket.
    • #pragma warn -par:
    • #pragma warn -rch: Ez az utasítás elrejti azokat a figyelmeztetéseket, amelyek akkor jelennek meg, ha egy függvény nem használja fel a neki átadott paramétereket: Ez az utasítás elrejti azokat a figyelmeztetéseket, amelyek akkor jelennek meg, ha egy kód elérhetetlen. Például: egy függvényben a return utasítás után írt bármely kód elérhetetlen.

Ez a cikk Harsh Agarwal közreműködésével készült. Ha tetszik a GeeksforGeeks és szeretnél hozzájárulni, írhatsz cikket a contribute.geeksforgeeks.org címen, vagy elküldheted a cikkedet a [email protected] címre. Láthatod, hogy a cikked megjelenik a GeeksforGeeks főoldalán, és segíthetsz más geekeknek.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.