Preprocesor zpracováná zdrojový text programu před použitím překladače. Nekontroluje syntaktickou správnost programu pouze provádí záměnu textů (např. symbolické jméno konstanty za její hodnotu). Řádky určené pro zpracování preprocessorem začínají znakem “#”, za kterým by neměla být mezera.
Ve vyraz lze použít
Definice konstanty obecně: #define jméno hodnota Příklady:
#define PI 3.14 #define AND && #define ERROR printf("Chyba v programu!");
Při zpracování preprocesorem je každý výskyt jména konstanty v následujícím textu zdrojového souboru nahrazen hodnotou této konstanty. Vyjímku tvoří výskyty jmen konstant uzavřené v uvozovkách, které se nenahrazují (např. printf (“Logická spojka AND…”);). Pokud je nutné změnit hodnotu konstanty je nutné ji nejprve zrušit a poté znova definovat. Příklad:
#undef PI #define PI 3.1416 /*lépe:*/ #ifdef PI #undef PI #define PI 3.1416 #endif /*Poznámka: Ludolfovo číslo jako double/float literál je #define-ováno v <limits.h> */
Pokud je potřeba definici konstatny zapsat na více než jeden řádek, zapíšeme na konci řádku znak “\”, který preprocesor z hodnoty konstanty vynechá a pokračuje ve zpracovávání hodnoty na následujícím řádku. Příklad:
#define DLOUHA_KONSTANTA 12345678.12345\
67890123456
Pozn.: pokračovacích řádků se spíše používá při #define makro(s,parametry) přdstavujících několik řádků kódu!
Pokud v programu často používáme funkci, která je tvořena velmi malým počtem příkazů, bývá výpočet značně neefektivní, protože “administrativa” spojená s voláním funkce je výpočetně náročnější než samotné provedení příkazů v těle funkce. Poznámka: toto lze řešit pomocí inline
Místo klasické funkce lze použít makro s parametry, které nevytváří žádnou “administrativu” za běhu programu. Nevýhodou maker je naopak vznik delšího (většího) programu a nemožnost použití rekurze.
Definice makra obecně: #define jméno(arg_1, …, arg_N) tělo_makra
kde arg_1 až arg_N jsou argumenty makra, které se chovají podobně jako
parametry u funkcí. Upozorňujeme, že mezi jménem makra a závorkou nesmí být mezera. Příklad:
#define na2(x) ((x)*(x))
Vzhledem k tomu, že při expanzi maker dochází pouze k nahrazení jednoho textu jiným, je doporučováno uzavřít celé tělo makra a také každý výskyt argumentu v těle makra do závorek. Příklady možných chyb:
#define na2(x) x*x ... v = na2(f-g); /* prepise se na v = f-g*f-g; */ #define cti(c) c=getchar() ... if (cti(c)=='A'){... /* prepise se na if (c=getchar()=='A'){... */
Podmíněný překlad (dále PP) používáme pro dočasné vynechání části zdrojového kódu při kompilaci. Typicky se PP používá pro
PP řízený konstantním výrazem Syntaxe obecně:
#if konstantní_výraz část_1 #else část_2 #endif
</code> Pokud je hodnota výrazu konstantní_výraz nenulová, překládá se část_1, jinak se překládá část_2. Části #else a část_2 lze vynechat. Příklad:
#define WINDOWS 1 ... #if WINDOWS #define JMENO "C:\\Data\\input.txt" #else #define JMENO "/data/input.txt" #endif
PP řízený definicí makra Syntaxe obecně:
#ifdef jméno_makra část_1 #else část_2 #endif
Pokud je makro jméno_makra definováno, překládá se část_1, jinak se překládá část_2. Opět platí, že části #else a část_2 lze vynechat. Příklad:
#define WINDOWS #ifdef WINDOWS #define JMENO "C:\\Data\\input.txt" #else #define JMENO "/data/input.txt" #endif
K dispozici je také direktiva #ifndef, která provádí opak výše zmíněné direktivy ifdef. Syntaxe obecně:
#ifndef jméno_makra část_1 #else část_2 #endif
Pokud je makro jméno_makra definováno, překládá se část_2, jinak se překládá část_1. I zde platí, že části #else a část_2 lze vynechat. Příklad:
#ifndef WINDOWS #define JMENO "/data/input.txt" #else #define JMENO "C:\\Data\\input.txt" #endif
Direktivy ifdef a ifndef testují pouze existenci jediného makra, pro konsturkci složitějších podmínek lze použít operátor defined() a logické operátory. Preprocesor také umožňuje složitější větvení PP pomocí direktivy #elif, která má podobný význam jako else if v podmínkovém příkazu. Pro úplnost dodáváme, že direktiva #error slouží pro výpis chyb (a ukončení překladu!) již při zpracovaní preprocesorem. Příklad:
#if defined(WINDOWS) && defined(DEBUG) #define LADENI 1 #elif !defined(DEBUG) #error Chyba nelze debugovat! #else #define LADENI 2 #endif
cc,upol