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:
- Makra
- Zapojení souborů
- Podmíněná kompilace
- 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:
#include <iostream>
#define LIMIT 5
int
main()
{
for
(
int
i = 0; i < LIMIT; i++) {
std::cout << i <<
"\n"
;
}
return
0;
}
#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:
#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;
}
#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:
- 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‘.
#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:
- #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()).
#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;
}
#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.
#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.