Jak název napovídá, preprocesory jsou programy, které zpracovávají náš zdrojový kód před kompilací. Mezi napsáním programu a jeho spuštěním v jazyce C/C++ je řada kroků. Podívejme se na tyto kroky dříve, než se skutečně začneme učit o preprocesorech.

Ve výše uvedeném diagramu můžete vidět mezikroky. Zdrojový kód napsaný programátory je uložen v souboru program.c. Tento soubor je poté zpracován preprocesory a je vygenerován rozšířený soubor zdrojového kódu s názvem program. Tento rozšířený soubor je zkompilován překladačem a je vygenerován soubor objektového kódu s názvem program.obj. Nakonec linker propojí tento soubor objektového kódu s objektovým kódem funkcí knihovny a vygeneruje spustitelný soubor program.exe.

Procesorové programy poskytují direktivy preprocesoru, které kompilátoru říkají, aby před kompilací předzpracoval zdrojový kód. Všechny tyto direktivy preprocesoru začínají symbolem ‚#‘ (hash). Symbol ‚#‘ znamená, že jakýkoli příkaz, který začíná symbolem #, je určen pro program preprocesoru a program preprocesoru tento příkaz provede. Příklady některých direktiv preprocesoru jsou: #include, #define, #ifndef atd. Pamatujte, že symbol # pouze udává cestu, kterou půjde do preprocesoru, a příkaz jako include zpracovává program preprocesoru. Například příkaz include zahrne do programu další kód. Tyto direktivy preprocesoru můžeme umístit kamkoli v našem programu.

Existují 4 hlavní typy direktiv preprocesoru:

  1. Makra
  2. Zapojení souborů
  3. Podmíněná kompilace
  4. Další direktivy

Poznejme nyní každou z těchto direktiv podrobněji.

  • Makra: Makra jsou části kódu v programu, kterým je přiřazen nějaký název. Kdykoli se překladač s tímto názvem setká, nahradí jej skutečným kusem kódu. K definici makra se používá direktiva ‚#define‘. Pochopme nyní definici makra pomocí programu:
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;
}



Výstup:

01234

V uvedeném programu je slovo LIMIT při provedení překladačem nahrazeno slovem 5. Slovo ‚LIMIT‘ v definici makra se nazývá šablona makra a ‚5‘ je rozšíření makra.

Poznámka: Na konci definice makra není středník(‚;‘). Definice maker nepotřebují na konci středník.

Makra s argumenty: Makrům můžeme také předávat argumenty. Makra definovaná s argumenty fungují podobně jako funkce. Pochopíme to na příkladu programu:

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;
}



Výstup:

Area of rectangle is: 50

Z výše uvedeného programu vidíme, že kdykoli kompilátor najde v programu AREA(l, b), nahradí jej příkazem (l*b) . A nejen to, hodnoty předané šabloně makra AREA(l, b) budou také nahrazeny příkazem (l*b). AREA(10, 5) se tedy bude rovnat 10*5.

  • Zařazení souboru: Tento typ direktiv preprocesoru říká překladači, aby do zdrojového kódu programu zahrnul soubor. Existují dva typy souborů, které může uživatel do programu zahrnout:
    • Hlavičkový soubor nebo Standardní soubory: Tyto soubory obsahují definice předdefinovaných funkcí jako printf(), scanf() atd. Tyto soubory musí být zahrnuty pro práci s těmito funkcemi. Různé funkce jsou deklarovány v různých hlavičkových souborech. Například standardní I/O funkce jsou v souboru ‚iostream‘, zatímco funkce provádějící operace s řetězci jsou v souboru ‚string‘.
      Syntaxe:
#include< file_name >

kde jméno_souboru je jméno souboru, který má být zahrnut. Závorky ‚<‚ a ‚>‘ říkají překladači, aby soubor hledal ve standardním adresáři.

  • uživatelsky definované soubory: Když se program stane velmi rozsáhlým, je dobré jej rozdělit do menších souborů a zahrnout, kdykoli je to potřeba. Tyto typy souborů jsou uživatelsky definované soubory. Tyto soubory lze zahrnout jako:
#include"filename"
  • Podmíněná kompilace: Podmíněné kompilační direktivy jsou typem direktiv, které pomáhají zkompilovat určitou část programu nebo vynechat kompilaci určité části programu na základě určitých podmínek. To lze provést pomocí dvou předzpracovávacích příkazů ‚ifdef‘ a ‚endif‘.
    Syntaxe:
#ifdef macro_name statement1; statement2; statement3; . . . statementN;#endif

Je-li definováno makro s názvem ‚macroname‘, pak se blok příkazů provede normálně, ale není-li definováno, kompilátor tento blok příkazů jednoduše přeskočí.

  • Další direktivy: Kromě výše uvedených direktiv existují ještě dvě direktivy, které se běžně nepoužívají. Jsou to např:
    • Směrnice #undef: Direktiva #undef se používá pro zrušení definice existujícího makra. Tato direktiva funguje jako:
#undef LIMIT

Použitím tohoto příkazu se zruší definice existujícího makra LIMIT. Po tomto příkazu se každý příkaz „#ifdef LIMIT“ vyhodnotí jako false.

  • #pragma Směrnice: Tato direktiva je účelová direktiva a slouží k zapnutí nebo vypnutí některých funkcí. Tento typ direktiv je specifický pro kompilátor, tj. liší se kompilátor od kompilátoru. Některé z direktiv #pragma jsou popsány níže:
    • #pragma startup a #pragma exit: Tyto direktivy nám pomáhají určit funkce, které je třeba spustit před spuštěním programu( před předáním řízení do main()) a těsně před ukončením programu (těsně před návratem řízení z main()).
      Poznámka: Níže uvedený program nebude fungovat s kompilátory GCC.
      Podívejte se na níže uvedený program:
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;
}



Výstup:

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

Výše uvedený kód poskytne při spuštění na kompilátorech GCC výstup, který je uveden níže:

Inside main()

Děje se tak proto, že GCC nepodporuje #pragma startup nebo exit. Pro podobný výstup na kompilátorech GCC však můžete použít níže uvedený kód.

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 Směrnice: Tato direktiva slouží ke skrytí varovných hlášení, která se zobrazují při kompilaci.
    Upozornění můžeme skrýt podle následujícího obrázku:
    • #pragma warn -rvl: Tato direktiva skryje ta varování, která se zobrazí, když funkce, která má vrátit hodnotu, hodnotu nevrátí.
    • #pragma warn -par:
    • #pragma warn -rch: Tato direktiva skryje ta varování, která jsou vyvolána, když kód není dosažitelný. Například: jakýkoli kód zapsaný za příkazem return ve funkci je nedosažitelný.

Tento článek napsal Harsh Agarwal. Pokud se vám GeeksforGeeks líbí a chtěli byste přispět, můžete také napsat článek pomocí stránky contribute.geeksforgeeks.org nebo poslat svůj článek na adresu [email protected]. Uvidíte, jak se váš článek objeví na hlavní stránce GeeksforGeeks, a pomůžete tak ostatním geekům.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.