ARCHIV |
|||||
Software (10844)
Distribuce (131)
Skripty (697)
Menu
Diskuze
Informace
|
C/C++ (13) - Preprocesor podruhéV dnešním dílu povídání o preprocesoru dokončíme. Probereme makra s parametry, standardní předdefinovaná makra a některé méně používané direktivy. Makro s parametryMinule jsem si ukázali, jak definovat jednoduché makro bez parametrů, nicméně podobně jako funkce i makro může mít parametry.
#define moje_gets(s, size) fgets((s), (size), stdin)
V dílu o standardním vstupu jsem haněl funkci gets a doporučoval místo ní fgets. Pokud programátora nebaví opisovat parametr stdin, může si pomoci výše uvedeným makrem. Je dobrým zvykem dávat parametry makra do závorek. Kdybychom třeba definovali makro pro násobení #define KRAT(a, b) a * b /* Správně je #define KRAT(a, b) ((a) * (b)) */ Rozvine se při volání KRAT(1 + 2, 3 + 4) na 1 + 2 * 3 + 4 Občas se hodí makro pro menší ze dvou čísel. Zde pomůže ternární operátor.
#define MINIMUM(a, b) ((a) < (b) ? (a) : (b))
Zejména v souvislosti s makry se často vyskytuje také operátor zapomenutí, čárka. Výraz x, y znamená nejprve vyhodnoť podvýraz x a hodnotu zapomeň, potom vyhodnoť podvýraz y a jeho hodnota bude výsledkem celého výrazu x, y. Celá konstrukce má smysl, pokud je na výrazu x podstatný jen jeho vedlejší efekt. Pokud nás například z ladících důvodu zajímá celkový počet volání putchar, můžeme jej volat prostřednictvím následujícího makra. int pocet_volani = 0; #define VOLEJ_PUTCHAR(c) (pocet_volani++, putchar((c))) Je dobré si uvědomit, že takto definované makro umožňuje přístup i k návratové hodnotě volání putchar, což by definice pomocí dvou příkazů ukončených středníkem neumožňovala. V programu tedy můžeme makro volat i takhle. int c = VOLEJ_PUTCHAR('A'); if (c == EOF) { puts("Chyba"); } Parametry makra samozřejmě nemusejí být jen proměnné nebo výrazy.
#define PROHOD(typ, a, b) {typ c; c = a; a = b; b = c;}
Uvedené makro prohodí obsah dvou proměnných libovolného typu. Volalo by se například int i = 1, j = 2; PROHOD(int, i, j) Rušení makraPři běžném způsobu programování v C není obvykle třeba definici makra rušit. Výjimka může nastat, pokud chceme definovat makro jen pro použití v hlavičkovém souboru, ale nechceme, aby bylo platné i v souboru, který jej inkluduje. Také se může stát, že nám vadí makro z nějakého hlavičkového souboru, jehož obsah nemůžeme ovlivnit. Zde pomůže příkaz #undef #undef MAKRO /* nebo obecněji */ #ifdef MAKRO #undef MAKRO #endif DrobnostiNěkteré direktivy preprocesoru často neznají ani ostřílení C programátoři. Sem patří #, ## a #line. Pomocí # lze parametr makra po rozvinutí obalit uvozovkami a udělat z něj řetězcovou konstantu, ## zase spojuje 2 tokeny do jednoho identifikátoru. #include <stdio.h> #define PRINT_TOKEN(x) puts(#x) #define PRINT_I(x) printf("%i\n", i##x) int main(void) { int i1 = 7, i2 = 8, i3 = 9; /* Pokud uhodnete, co vypíše PRINT_TOKEN(1 + 1); rozumíte preprocesoru */ PRINT_TOKEN(1 + 1); PRINT_I(1); /* printf("%i\n", i1); */ PRINT_I(2); /* printf("%i\n", i2); */ PRINT_I(3); /* printf("%i\n", i3); */ return 0; } O něco častěji se používá #pragma, tato direktiva má obvykle ještě parametr. Pokud mu překladač nerozumí, musí podle normy celou direktivu ignorovat. V opačném případě ji implementačně závislým způsobem zpracuje. Například pomocí #pragma warning( disable : 4507 ) můžeme v MS Visual C++ zakázat jedno konkrétní varovné hlášení při překladu kódu, který se zdá překladači podezřelý. Při použití jiného překladače (např. gcc), který tuto syntaxi direktivy #pragma nezná, nedojde k chybě, pouze bude celá direktiva ignorována. Standardní makraANSI C definuje několik maker
Direktiva #line ovlivňuje předdefinovaná makra __LINE__ a __FILE__.
#line 174 "soubor.c"
Tato direktiva může být použita v generátorech C kódu z nějakého metazdrojáku, případná chybová hlášení (využívající __LINE__ a __FILE__) přeloženého vygenerovaného C kódu tak mohou být nastavena na původní metakód. Běžný programátor tedy #line asi nikdy nevyužije.
Příklad pro dnešní dílPři vývoji větších projektů je dobrým zvykem umožnit logování událostí za běhu programu. V distribuční verzi může (ale nemusí) být žádoucí logování potlačit a logovací kód vůbec nepřekládat a nelinkovat do programu. V příkladu definuji makro ZALOGUJ, které se rozvine buď na prázdný řetězec, nebo na výpis logovací hlášky v závislosti na symbolu LOGOVAT. Všimněte si použití standardních maker __FILE__ a __LINE__. /* gcc program.c -o program -DLOGOVAT */ #include <stdio.h> #ifdef LOGOVAT #define ZALOGUJ(s) printf("%s:%i %s\n", __FILE__, __LINE__, (s)) #else #define ZALOGUJ(s) #endif int main(void) { ZALOGUJ("Začátek programu"); return 0; } Pokračování příštěPříště se podíváme podrobněji na funkce. Postupně se také začneme zabývat projekty s větším počtem zdrojových souborů.
Související články
Předchozí Celou kategorii (seriál) Další
C/C++ (1) - Úvod
C/C++ (2) - První program C/C++ (3) - Proměnné a konstanty C/C++ (4) - Funkce printf C/C++ (5) - Funkce printf podruhé C/C++ (6) - Operátory C/C++ (7) - Podmínka C/C++ (8) - Cykly C/C++ (9) - Pole C/C++ (10) - Standardní vstup a výstup C/C++ (11) - Čtení a konverze čísel C/C++ (12) - Preprocesor C/C++ (14) - Funkce C/C++ (15) - Proměnné C/C++ (16) - Hlavičkové soubory C/C++ (17) - Makefile C/C++ (18) - Makefile podruhé C/C++ (19) - Příkaz switch a bitové operátory C/C++ (20) - Alokace paměti C/C++ (21) - Práce s řetězci C/C++ (22) - Struktury C/C++ (23) - Seznam C/C++ (24) - Soubory C/C++ (25) - Funkce s proměnným počtem parametrů C/C++ (26) - Standardní knihovna C/C++ (27) - Standardní knihovna podruhé C/C++ (28) - Standardní knihovna potřetí C/C++ (29) - Standardní knihovna počtvrté C/C++ (30) - Výčtový typ a nestandardní knihovny C/C++ (31) - Jazyk C++, historie, charakteristika, vztah k C C/C++ (32) - Omezení C++ oproti C C/C++ (33) - Rozdíly mezi C a C++ C/C++ (34) - Drobná vylepšení C++ C/C++ (35) - Reference, funkce C/C++ (36) - Prostory jmen C/C++ (37) - Prostory jmen podruhé C/C++ (38) - Prostory jmen potřetí C/C++ (39) - Objektově orientované programování C/C++ (40) - Dědičnost a virtuální metody GCC vs. CLANG C++ Binární vyhledávací stromy C++ Datová struktura zásobník C++ - Hashování C++ - Vyhledávání v textu - Brute Force algoritmus C++ šablony Grafy a grafové algoritmy I Grafy a grafové algoritmy II C++ výjimky C++ Funktory neboli funkční objekty Grafy a grafové algoritmy III. C++ a garbage collector Předchozí Celou kategorii (seriál) Další
|
Vyhledávání software
Vyhledávání článků
28.11.2018 23:56 /František Kučera 12.11.2018 21:28 /Redakce Linuxsoft.cz 6.11.2018 2:04 /František Kučera 4.10.2018 21:30 /Ondřej Čečák 18.9.2018 23:30 /František Kučera 9.9.2018 14:15 /Redakce Linuxsoft.cz 12.8.2018 16:58 /František Kučera 16.7.2018 1:05 /František Kučera
Poslední diskuze
31.7.2023 14:13 /
Linda Graham 30.11.2022 9:32 /
Kyle McDermott 13.12.2018 10:57 /
Jan Mareš 2.12.2018 23:56 /
František Kučera 5.10.2018 17:12 /
Jakub Kuljovsky | |||
ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2024) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze |