C Esiprosessorit

C Esiprosessorit

Esiprosessorit ovat ohjelmia, jotka käsittelevät lähdekoodin ennen varsinaisen kääntämisen alkamista. Ne eivät ole osa käännösprosessia, mutta ne toimivat erikseen, jolloin ohjelmoijat voivat muokata koodia ennen kääntämistä.

  • Se on ensimmäinen vaihe, jonka C-lähdekoodi käy läpi, kun se muunnetaan suoritettavaksi tiedostoksi.
  • Esikäsittelydirektiivien päätyypit ovat  Makrot Tiedoston sisällyttämisen ehdollinen käännös ja muut käskyt, kuten #undef #pragma jne.
  • Pääasiassa näitä direktiivejä käytetään korvaamaan tietty C-koodin osa toisella C-koodilla. Jos esimerkiksi kirjoitamme '#define PI 3.14', esiprosessori korvaa PI:n 3.14:llä.
C Esiprosessorit

C-esiprosessorien tyypit

Kaikki edellä mainitut esiprosessorit voidaan luokitella 4 tyyppiin:

Makrot

Makrot käytetään määrittämään vakioita tai luomaan funktioita, jotka esikäsittelijä korvaa ennen koodin kääntämistä. Kaksi esiprosessoria #määritellä ja #undef käytetään makrojen luomiseen ja poistamiseen C:ssä.

#määritellä tokenin arvo
#undef merkki

missä esikäsittelyn jälkeen merkki laajennetaan siihen arvo ohjelmassa.

Esimerkki:

C
   #include         // Macro Definition   #define LIMIT 5   int     main  (){      for     (  int     i     =     0  ;     i      <     LIMIT  ;     i  ++  )     {      printf  (  '%d   n  '       i  );      }      return     0  ;   }   

Lähtö
0 1 2 3 4  

Yllä olevassa ohjelmassa ennen kääntämisen alkamista sana LIMIT korvataan 5:llä. Sana 'RAJOITTAA' makron määritelmässä kutsutaan makromalliksi ja "5" on makrolaajennus.

Huom Makromääritelmän lopussa ei ole puolipistettä (;). Makromääritelmät eivät tarvitse puolipistettä loppuakseen.

On myös joitain Ennalta määritetyt makrot C:ssä jotka ovat hyödyllisiä tarjoamalla ohjelmallemme erilaisia ​​toimintoja.

Aiemmin määritetty makro voidaan määrittää määrittelemättömäksi käyttämällä #undef esikäsittelyohjelmaa. Esimerkiksi yllä olevassa koodissa

C
   #include         // Macro Definition   #define LIMIT 5   // Undefine macro   #undef LIMIT   int     main  (){      for     (  int     i     =     0  ;     i      <     LIMIT  ;     i  ++  )     {      printf  (  '%d   n  '       i  );      }      return     0  ;   }   


Lähtö:

 ./Solution.c: In function 'main': ./Solution.c:13:28: error: 'MAX' undeclared (first use in this function) printf('MAX is: %dn' MAX); ^ ./Solution.c:13:28: note: each undeclared identifier is reported only once for each function it appears in  

Makrot argumenteilla

Voimme myös välittää argumentteja makroille. Nämä makrot toimivat samalla tavalla kuin funktiot. Esimerkiksi

# määritellä foo(a b) a + b
#define func(r) r * r

Ymmärrämme tämän ohjelman avulla:

C
   #include         // macro with parameter   #define AREA(l b) (l * b)   int     main  (){      int     a     =     10       b     =     5  ;          // Finding area using above macro      printf  (  '%d'       AREA  (  a       b  ));      return     0  ;   }   

Lähtö
Area of rectangle is: 50  

Selitys: Yllä olevassa ohjelmassa makro ALUE(l b) on määritetty laskemaan suorakulmion pinta-ala kertomalla sen pinta-ala pituus (l) ja leveys (b) . Kun ALUE(a b) kutsutaan sitä laajenee (a * b) ja tulos lasketaan ja tulostetaan.

Katso Makrotyypit C:ssä lisää esimerkkejä ja tyyppejä.

Tiedoston sisällyttäminen

Tiedostojen sisällyttäminen mahdollistaa ulkoisten tiedostojen (otsikkotiedostokirjastojen jne.) sisällyttämisen nykyiseen ohjelmaan. Tämä tehdään yleensä käyttämällä #sisällytä direktiivi, joka voi sisältää sekä järjestelmän että käyttäjän määrittämiä tiedostoja.

Syntaksi

On kaksi tapaa sisällyttää otsikkotiedostoja.

#sisältää
#sisältää 'tiedostonimi'

The ' <' ja '>' suluissa käske kääntäjää etsimään tiedosto tiedostosta vakiohakemisto samalla kun lainausmerkit ( ' ' ) käske kääntäjää etsimään otsikkotiedostoa lähdetiedoston hakemistosta.

Esimerkki:

C
   // Includes the standard I/O library   #include            int     main  ()     {      printf  (  'Hello World'  );          return     0  ;   }   

Lähtö
Hello World 

Ehdollinen kokoelma

Ehdollinen kokoelma voit sisällyttää tai jättää pois koodin osia tietyistä ehdoista riippuen. Tämä on hyödyllinen alustakohtaisen koodin luomisessa tai virheenkorjauksessa. On olemassa seuraavat ehdolliset esikäsittelykäskyt: #if #ifdef #ifndef else #elif ja #endif

Syntaksi

Ehdollisten esiprosessorien yleinen syntaksi on:

#jos
// joku koodi
#elif
// lisää koodia
#muu
// Lisää koodia
#endif

#endif-käskyä käytetään sulkemaan #if #ifdef- ja #ifndef-avauskäskyt.

Esimerkki

C
   #include         // Defining a macro for PI   #define PI 3.14159   int     main  (){       // Check if PI is defined using #ifdef   #ifdef PI      printf  (  'PI is defined  n  '  );   // If PI is not defined check if SQUARE is defined   #elif defined(SQUARE)      printf  (  'Square is defined  n  '  );   // If neither PI nor SQUARE is defined trigger an error   #else      #error 'Neither PI nor SQUARE is defined'   #endif   // Check if SQUARE is not defined using #ifndef   #ifndef SQUARE      printf  (  'Square is not defined'  );   // If SQUARE is defined print that it is defined   #else      printf  (  'Square is defined'  );   #endif      return     0  ;   }   

Lähtö
PI is defined Square is not defined 

Selitys: Tämä koodi käyttää ehdollisia esikäsittelyohjeita ( #ifdef #elif ja #ifndef ) tarkistaaksesi, ovatko tietyt makrot ( PI ja NELIÖ ) on määritelty. Koska PI on määritelty, ohjelma tulostaa PI on määritelty ' tarkistaa sitten, ettei NELIÖ ole määritetty ja tulostaa Neliötä ei ole määritelty '.

Muut direktiivit

Ensisijaisten esikäsittelyohjeiden lisäksi C tarjoaa myös muita direktiivejä kääntäjien käyttäytymisen ja virheenkorjauksen hallintaan.

#pragma:

Antaa kääntäjälle erityiset ohjeet sen käyttäytymisen hallitsemiseksi. Sitä käytetään poistamaan käytöstä varoitusasetusten kohdistus jne.

Syntaksi

#pragma direktiivi

Joitakin #pragma-direktiivejä käsitellään alla: 

  1. #pragma startup: Nämä käskyt auttavat meitä määrittämään funktiot, jotka on suoritettava ennen ohjelman käynnistystä (ennen kuin ohjaus siirtyy main()-funktioon).
  2. #pragma poistu : Nämä käskyt auttavat meitä määrittämään funktiot, jotka on suoritettava juuri ennen ohjelman lopettamista (juuri ennen kuin ohjaus palaa main()-funktiosta).

Esimerkki

C
   #include         void     func1  ();   void     func2  ();   // specifying funct1 to execute at start   #pragma startup func1   // specifying funct2 to execute before end   #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  ;   }   

Lähtö
Inside main()  

Yllä oleva koodi tuottaa yllä olevan tulosteen, kun se ajetaan GCC-kääntäjillä, kun odotettu tulos oli:

Odotettu tulos

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

Tämä johtuu siitä, että GCC ei tue #pragma käynnistystä tai lopettamista. Voit kuitenkin käyttää alla olevaa koodia odotettuun tulokseen GCC-kääntäjissä. 

C
   #include         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  ;   }   

Lähtö
Inside func1() Inside main() Inside func2()  

Yllä olevassa ohjelmassa olemme käyttäneet joitain tietyt syntaksit niin, että yksi funktioista suoritetaan ennen päätoimintoa ja toinen pääfunktion jälkeen.

Luo tietokilpailu