7.0 Makra
7.0.1 Makra bez parametrů
    Makra je specialita Céčka. Usnadní hodně práce při psaní, nejlepší bude když
    je vysvětlím pomocí příkladů. Makra se v C definují jako příkaz preprocesouru
    (se znakem # vězení na začátku) :

    #define JMENOMAKRA hodnotamakra

    Pozor ! Mezi JMENOMAKRA a hodnotamakra musí být mezera !

    Potom, pokud se kdekoli (kromě jedné výjimky, popíšu dále) v programu
    objeví JMENOMAKRA, kompilátor ji zamění za "hodnotamakra". Makra
    se většinou píší velkými písmeny, ale pokud je malými, nebo oboje, není to chyba. 
    A teď k té výjimce... pokud je makro ve stringu, nebo komentáři, neprojeví se :


#define JMENO Luki

printf("Jmenuji se JMENO");
Vypíše : Jmenuji se JMENO a ne očekávané : Jmenuji se Luki A nyní praktický příklad :

#define PI 3.14159265

double uhel, radiany;

radiany = uhel * PI / 180.0;
A teď ještě malá pomůcka :

#define MAKRO toto je makro, které se nevejde \
    na více řádků ... 
Makro taky může něco dělat :

#define DO_IT { printf("Cekam !\n"); getchar(); }
Tohle makro vytiskne "Cekam !" a čeká na stisk klávesy. Další použití makra je v tzv. podmíněném překladu : 7.0.1.1 Podmíněný překlad Podmíněný překlad se používá třeba když máte dvě verze části programu, každou pro jinou platformu. Nebo když máte část použitou pro ladění a pro běh programu. Dělá se to pomocí maker :

#define LINUX 1
#define WINDOWS 0
#define WIN_NT 0

#if LINUX
    // ... funkce, specificke pro linux
#elif WINDOWS && WIN_NT
    // ... funkce, specificke pro windows NT
#elif WINDOWS
    // ... funkce, specificke pro windows
#else
    // ... funkce pro dos
#endif
Tohle dokáže rozhodnout, která část programu se bude překládat podle toho, jakou hodnotu mají makra (1 = pravda, 0 = nepravda). Jde to i jinak :

#define LINUX
// #define WINDOWS
// #define WIN_NT

#if defined(LINUX)
    // ... funkce, specificke pro linux
#elif defined(WINDOWS) && defined(WIN_NT)
    // ... funkce, specificke pro windows NT
#elif defined(WINDOWS)
    // ... funkce, specificke pro windows
#else
    // ... funkce pro dos
#endif
Tady stačí, aby makro bylo definováno, nemusí mít žádnou hodnotu. No a pokud nepotřebujete nic takového složitého, je tu ještě jedna možnost :

#define DEBUG
//#define RELEASE

#ifdef DEBUG
    // ... funkce pro ladění (třeba výpisy stavu programu ..)
#endif

#ifndef RELEASE
    // ... jde to i naopak
#endif
Tohle je příklad pro příkazy #ifdef, #ifndef. To se používá jěště u funkcí. ale o tom až u nich. 7.0.1 Makra s parametry Definují se skoro stejně :

#define MAX(x,y) ((x) > (y))? (x) : (y)
// Toto makro vybere maximální číslo ze dvou
// Volá se a = MAX(b, c); kde a, b a c jsou nějaké proměnné
Pozor ! Mezi jménem makra (MAX) a parametry (x,y) nesmí být mezera, mezi parametry a hodnotou makra musí být mezera. Možná se divíte, proč mám to x a y v závorkách : Pokud jste četli předchozí část kapitoly o makrech, víte jak se makro rozvíjí a proto kdyby tam nebyly, stalo by se asi tohle ...

#define MAX(x,y) (x > y)? x : y
// zde je záměrně CHYBA
Volání :

int a, b, c;

a = MAX(b + 1, c - 2);
A chybný rozvoj :

a = (b + 1 > c - 2)? b + 1 : c - 2 ;
Podmínka se nevyhodnotí jak asi čekáte, ale (1 > c) + b - 2. To je správná (syntakticky)podmínka a pokud vyjde nenulová, program si myslí že platí. A se závorkami :

#define MAX(x,y) ((x) > (y)) ? (x) : (y)

a = ((b + 1) > (c - 2)) & (b + 1) : (c - 2);
7.1 Paměťové modifikátory 7.1.0 Modifikátor auto Pokud deklarujete proměnnou bez modifikátorů, je deklarovaná právě, jako auto. int i; je to samé jako : auto int i; 7.1.1 Modifikátor static Pokud je proměnná deklarovaná jako : static int i; Není přístupná z ostatních modulů, ale pokud je globální, zůstává globální i nadále. Pokud je ale lokální, zůstává v ní její hodnota. To si ale vysvětlíme až u funkcí. Výhoda tohoto modifikátoru je zrychlení. 7.1.2 Modifikátor register Pokud deklarujete proměnnou jako : register int i; Může být tato proměnná uložená v registru procesoru a proto je mnohokrát (až brutálně)rychlejší. Jen si musíte pamatovat že registrů je proklatě málo a tak ne všechny proměnné můžou být v registru. (většinou to vyjde tak na dvě) 7.1.3 Modifikátor volatile Pokud není z nějakého důvodu vhodné, aby byla proměnná uložená v registru, deklarujeme ji : volatile int i; ... a ona proměnná bude pouze v paměti RAM. To se používá ve vícevláknovém programování pro různé stavové proměnné nebo při spolupráci více paralelně běžících programů. Ale o tom až někdy ... 7.2 Příkaz #include Tímto příkazem vkládáte hlavičkové soubory, pokud je syntaxe : #include <stdio.h> Vložíte systémový soubor stdio.h, ale pokud to bude : #include "main.h" Vložíte soubor main.h, který kompilátor očekává v adresáři projektu. A teď k čemu je to dobré ... Pokud už jste zkoušeli napsat v C-čku něco většího, kde se funkce volají mezi sebou, asi jste narazili nachybu, že některé funkce nejdou najít ... Funkce má narozdíl od pro - měnné deklaraci - to je řádek, kde je funkce vypsána ten je povinný. a taky definici, čili funkční prototyp a to je řádek, podle kterého kompilátor pozná, že funkce se někde v programu vyskytuje ... Tvoří se asi takhle : funkce :

int Nejake_Volani(int parametr){
    return parametr + 1;
}
má funkční prototyp :

int Nejake_Volani(int parametr); // Ten středník musí být
Tohle sice patří k preprocesoru, ale jak to využít si povíme až u funkcí za dvě kapitoly. Cvičení : 1) - Napište program, který pomocí makra zjistí pokud je zadané číslo liché. 2) - Napište makro, které vybere prostřední ze tří zadaných čísel (velikostně) 3) - Napište které zjistí zda znak je malé písmeno. (hodnota bude větší nebo rovno 'a' a menší nebo 'z') 4) - Napište makro pro třetí mocninu (x * x * x). Vyzkoušejte na : - na_treti(10); - na_treti(i + 10); - na_treti(i * 10); - na_treti(i * j - 3); (i a j jsou zadaná čísla) 5) - Napište makro pro výpis chybové hlášky a čekání na stisk klávesy. (použijte čárku) ~Hare Krishna~ -tHE SWINe-
Zpátky