A C és C++ nyelvek igen fontos és hasznos eleme az elÅ‘feldolgozó, másnéven a preprocesszor. Emiatt a nyelv fordÃtása két lépcsÅ‘s. ElÅ‘ször az elÅ‘feldolgozó utasÃtásai kerülnek feldolgozásra és csak ezután történik meg a tényleges nyelvi fordÃtás.
Az elÅ‘feldolgozó megÃtélése ambivalens, mivel hasznos, viszont sok galibát tud okozni. A galibák többsége abból fakad, hogy az elÅ‘feldolgozó utasÃtásaival létrehozhatóak makrók, amik úgy viselkednek, mint a függvények, viszont tényleges függvényhÃvást nem váltanak ki, mivel a feldolgozáskor a hÃvás helyére egyszerűen csak bemásolódik a kód.
//c++ makró példa
#include <iostream>
using namespace std;
#define egy cout
#define ketto <<
#define harom "Hello World!\n"
int main()
{
//ide az egy ketto és harom szimbólum értékei másolódnak be.
//Látszólag azonban bÅ‘vÃtettük a nyelvet új kulcsszókkal
egy ketto harom;
return 0;
}
A program kimenete:
Hello World!
Ezért a makrókban nagyon nehéz hibát keresni. Emiatt C# esetén nem létezik a klasszikus értelemben vett elÅ‘feldolgozó. Makrók és összetett szimbólumok nem definiálhatók. Az egyszerű szimbólumok logikai tÃpusként foghatók fel és C# esetén leginkább feltételes fordÃtás létrehozásának eszközei.
Feltételes fordÃtás alatt az értendÅ‘, hogy például adott egy program demó és teljes verziója. Gazdasági okokból a teljes verzió fejlesztésén dolgozik a csapat gÅ‘zerÅ‘vel, viszont jó lenne néha egy demó verziót kiadni.
Ebben az esetben két lehetőség előtt áll a fejlesztőcsapat. Lemásolja a meglévő teljes verziót egy másik projektbe, majd törli a felesleges részeket. Ez minden egyes demó változat létrehozásakor iszonyatosan sok munkával járhat.
A másik, gazdaságosabb és hatékonyabb megoldás a feltételes fordÃtás. Az elÅ‘feldolgozó eszközeivel a demó verzióban egy feltételesen forduló blokkban megjelöljük a nem kÃvánatos részeket.
Ezután a program fordÃtásakor és kiadásakor csupán annyi teendÅ‘ van, hogy definiáljuk (vagy nem) a megfelelÅ‘ szimbólumot, amit a feltételes blokkjaink figyelnek és máris két verziójával rendelkezhetünk a szoftvernek.
Az elÅ‘feldolgozó utasÃtásai kettÅ‘skereszt karakterrel kezdÅ‘dnek. A következÅ‘ utasÃtások támogatottak:
#if
#else
#endif
#elif
#region
#endregion
#define
A #define utasÃtással tudunk szimbólumot definiálni. A szimbólumnak értéke nem lehet. Alapértelmezetten a környezet két szimbólumot definiál nekünk: ezek a DEBUG és a RELEASE, amelyek a két alapvetÅ‘ fordÃtási konfigurációt (Build Configuration) határozzák meg.
A Debug változat a hibakeresésre szánt változata egy programnak. Ezen változat kiegészÃtÅ‘ nyomkövetési információkat tartalmaz a hibakeresÅ‘ (debugger) számára. Éles környezetbe ilyet nem érdemes kiadni, mivel lassabban fut, mint a Release változat.
A Release változat nem tartalmazza a hibakereséshez szükséges extra információkat, Ãgy gyorsabban tud futni. Cserébe nem tudunk benne hibát keresni. Végfelhasználóknak a programunknak ezen változatát érdemes kiadni.
A build konfigurációk között az eszköztáron tudunk egyszerűen váltani. Saját Build konfigurációk is készÃthetÅ‘k a Configuration manager segÃtségével.
A #define egy szimbólumot csak az adott fájl számára definiál. A #define utasÃtások csak a fájl elején lehetnek, még a tényleges C# kód elÅ‘tt.
Ha egész projekt szinten szeretnénk definiálni egy szimbólumot, akkor azt a projekt tulajdonságainál tudjuk megtenni, a Build lapon. Itt az elsÅ‘ beállÃtási lehetÅ‘ség a Conditional compilation symbols sor. Itt vesszÅ‘vel elválasztva megadhatjuk az egész projekt fordÃtásánál definiált szimbólumokat.
Megjegyzem, hogy konfiguráció váltás esetén a projekt beállÃtásai is megváltoznak, mivel minden konfigurációhoz külön tárolódnak a projekt beállÃtások. Tehát, ha valami szimbólumot beállÃtunk Debug konfigurációban, az nem fog öröklÅ‘dni, másolódni a Release konfigurációba.
Azért, hogy a szimbólumok és a változónevek között egyértelműen különbséget lehessen tenni, kódolási konvencióként elfogadott, hogy az előfeldolgozó szimbólumait csupa nagybetűvel adjuk meg.
A #region utasÃtás egy régiót határoz meg a forráskódunkon belül. Arra használható, hogy a kód már kész régióit átláthatóbbá, összecsukhatóvá tegyük, akár blokkon kÃvül, vagy belül. Ez az egyetlen olyan elÅ‘feldolgozó utasÃtás, ami inkább a kód átláthatóságát hivatott javÃtani.
A #region utasÃtás után egy tetszÅ‘legesen hosszú szövegnek kell állna. Ez a szöveg fog megjelenni a szerkesztÅ‘ben, ha a blokk össze van csukva. A blokk végét az #endregion utasÃtás határozza meg. A régiók egymásba úgy nem ágyazhatóak, mint a hagyományos vezérlési blokkok.
Az #if, #elif, #else, #endif utasÃtásokkal szimbólumok meglétét tudjuk ellenÅ‘rizni. Az utasÃtások működései megegyeznek a hagyományos nyelvi if, else, else if utasÃtásokkal. Ugyanúgy feltétel esetén több szimbólum is megadható VAGY (II), ÉS (&&), NEM (!) kapcsolat segÃtségével.
Az alábbi példa az előfeldolgozó használatát mutatja be:
#define TESZT
using System;
namespace PeldaElofeldolgozo
{
class Program
{
static void Main(string[] args)
{
#region összecsukható régió
//ide egy komolyabb kód szösszenet Ãrható
//ami összecsukható lesz Visual Studio-ban
#endregion
#if DEBUG
Console.WriteLine("DEBUG mód!");
#if TESZT
Console.WriteLine("Teszt definiálva");
#endif
#else
Console.WriteLine("RELEASE mód!");
#if TESZT
Console.WriteLine("Teszt definiálva");
#endif
#endif
Console.ReadKey();
}
}
}
A program kimenete RELASE konfigurációban:
RELEASE mód!
Teszt definiálva