Preprocesor jazyka C: Porovnání verzí

Smazaný obsah Přidaný obsah
m odkaz
m Robot: -zastaralá značka HTML; kosmetické úpravy
Řádek 4:
# Nahrazení trigramů (v podstatě jde o [[escape sekvence]], které umožňují zadávání potřebných 7-bit [[ASCII]] znaků i z jiných, většinou starších kódových tabulek).
# Spojení řádků – fyzické řádky zdrojového textu, které jsou zakončeny escape-sekvencí nového řádku (v podstatě jde o obrácené lomítko \ použité jako poslední znak na řádku), jsou spojeny do jediného logického řádku.
# Tokenizace – preprocesor zalomí výsledek do posloupnosti tzv. ''tokenů preprocesoru'' a ''bílých znaků'' (mezery, tabelátory a konce řádků). Komentáře jsou nahrazeny ''bílým znakem''.
# Přepsání maker a provedení direktiv - v této fázi jsou expandována makra a provedeny direktivy, jako např. vložení zdrojového kódu z jiného souboru nebo vynechání části zdrojového kódu v případě podmíněného překladu.
 
Řádek 12:
Nejčastěji využívanou direktivou preprocesoru je vložení jiného souboru:
 
<sourcesyntaxhighlight lang="c">
#include <stdio.h>
 
Řádek 20:
return 0;
}
</syntaxhighlight>
</source>
 
V tomto případě direktiva <code>#include</code> vložila na začátek zdrojového souboru obsah souboru <code>stdio.h</code>, který musí být v systému uložen ve specifickém adresáři (v [[UN*X|unixových systémech]] v adresáři <code>/usr/include</code>).
Řádek 27:
Direktivy <code>#if</code>, <code>#ifdef</code>, <code>#ifndef</code>, <code>#else</code>, <code>#elif</code> a <code>#endif</code> umožňují podmíněný překlad vybraných částí zdrojového kódu.
 
<sourcesyntaxhighlight lang="c">
#define __WINDOWS__
 
Řádek 35:
#include <unistd.h>
#endif
</syntaxhighlight>
</source>
 
Symbol není nutné definovat ve zdrojovém kódu, jako je tomu v předcházejícím příkladě s <code>#define __WINDOWS__</code>, ale lze jej definovat až při překladu jako jeden z atributů preprocesoru, popřípadě kompilátoru. Viz následující příklad:
 
<sourcesyntaxhighlight lang="c">
#include <stdio.h>
 
int main(void){
#ifdef CZ
printf("Ahoj\n");
#else
Řádek 51:
return 0;
}
</syntaxhighlight>
</source>
 
Při překladu pak použijeme:
 
<sourcesyntaxhighlight lang="bash">
$gcc -Wall ahoj.c -o ahoj
$./ahoj
Řádek 63:
$./ahoj
Ahoj
</syntaxhighlight>
</source>
 
Poprvé je soubor s kompilován bez definovaného symbolu <code>CZ</code> a v kódu bude tedy použit řádek <code>printf("Hello\n");</code>. V druhém případě je jedním z parametrů při volání kompilátoru <code>-DCZ</code>, takže symbol <code>CZ</code> bude nadefinován ještě před spuštěním preprocesoru a v kódu se proto použije řádek <code>printf("Ahoj\n");</code>. Následující příkaz <code>./ahoj</code> spouští překompilovaný soubor.
Řádek 69:
Podmíněný překlad se často používá k tomu, aby zabránil vícenásobnému vložení téhož kódu. Následující příklad zajistí, že kód bude vložen pouze jednou, bez ohledu na to, kolikrát bude direktivou <code>#include</code> vložen soubor, který jej obsahuje. Konstrukce je užitečná při tvorbě složitějších programů, složených z mnoha souborů:
 
<sourcesyntaxhighlight lang="c">
#ifndef SOUBOR_A
#define SOUBOR_A
Řádek 76:
...
#endif
</syntaxhighlight>
</source>
 
=== Definice a expanze maker ===
Používají se dva základní typy definice maker. Jednak lze definovat makra bez parametru, která expandují vždy do stejné sekvence znaků (resp. tokenů), jednak lze definovat makra s parametry, které se z praktického hlediska chovají podobně jako [[Funkce (programování)|funkce]]. Obecná syntaxe direktivy <code>#define</code> je:
 
<sourcesyntaxhighlight lang="c">
#define <identifikátor> <seznam nahrazujících tokenů>
#define <identifikátor>(<seznam parametrů>) <seznam nahrazujících tokenů>
</syntaxhighlight>
</source>
 
Speciálním případem je definice samotného identifikátoru, kterému není přiřazen žádný další seznam tokenů – příklad použití takovéto definice byl uveden v sekci ''Podmíněný překlad''.
 
Příkladem makra, které nepřijímá žádné parametry, může být následující použití preprocesoru k definici číselné konstanty:
 
<sourcesyntaxhighlight lang="c">
#define PI 3.14159
</syntaxhighlight>
</source>
 
Příkladem makra, které přijímá parametr (argument):
 
<sourcesyntaxhighlight lang="c">
#define RADTODEG(x) ((x) * 57.29578)
</syntaxhighlight>
</source>
 
Při použití takto definovaného makra se nesmí mezi názvem makra a závorkou, ve které je uveden jeden nebo více parametrů (argumentů), vyskytovat žádné bílé znaky (tj. nesmí tam být uvedena mezera).
Řádek 104:
Specifickým rysem maker C preprocesoru z hlediska programování v jazyce C je to, že jde pouze o zestručněný zápis zdrojového kódu (podobně jako v případě některých skriptovacích jazyků) – nikoliv o skutečnou definici funkce. Proto parametry maker nepodléhají [[Typová kontrola|typové kontrole]] jazyka C. Tento zápis se nechová jako funkce a někdy to může vést k obtížně odhalitelným chybám. Například v tomto případě, kde je makro <code>NASOBEK</code> definováno takto:
 
<sourcesyntaxhighlight lang="c">
#define NASOBEK(a,b) a*b
</syntaxhighlight>
</source>
 
a je použité ve výrazu:
 
<sourcesyntaxhighlight lang="c">
c=NASOBEK(2+2,5+5)
</syntaxhighlight>
</source>
 
bude expandováno jako:
 
<sourcesyntaxhighlight lang="c">
c=2+2*5+5
</syntaxhighlight>
</source>
 
Výsledek není mylně očekávaných 40 ale 17. Takové chybě se dá v tomto konkrétním případě zabránit uzavřením matematického výrazu do závorek (podobně jako u ukázkového makra <code>RADTODEG(x)</code> v předchozím příkladu). Obecným řešením je nepoužívání nadměrně komplikovaných maker. V tomto konkrétním případě stačí dané makro přepsat jako:
 
<sourcesyntaxhighlight lang="c">
#define NASOBEK(a,b) ((a)*(b))
</syntaxhighlight>
</source>
 
Obtížněji řešitelným problémem je tzv. vícenásobná evaluace (vyhodnocení) parametrů makra – pokud je parametrem makra např. volání funkce, tak na rozdíl od obyčejného volání funkce, kdy by byla funkce zavolána jen jednou a pak se pracovalo s její návratovou hodnotu, je v případě makra funkce zavolána pokaždé, když se definice makra odkazuje na daný parametr. Kromě volání funkcí je toto chování nepříjemné např. i při použití specifických C operátorů jako <code>++</code>, <code>−−</code> apod.
Řádek 130:
Pokud je to potřeba, lze definici makra zrušit (odstraňuje makra s parametry i makra bez parametru):
 
<sourcesyntaxhighlight lang="c">
#undef <identifikátor>
</syntaxhighlight>
</source>
 
=== Speciální makra a direktivy ===