LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (12) - Preprocesor

Před vlastním překladem se dostane ke slovu preprocesor. S jeho pomocí můžeme například definovat konstantu, vložit soubor nebo překládat jen část zdrojového souboru.

18.1.2005 15:00 | Jan Němec | Články autora | přečteno 34804×

Tři fáze překladu

Celý proces překladu od zdrojového kódu v C až po spustitelný soubor má 3 fáze. Nejprve se dostane ke slovu preprocesor, následuje vlastní překlad a závěrečnou fází je linkování. Kód programu tvoří jeden nebo více *.c souborů, preprocesor zpracovává každý zvlášť. Provádí úpravy na textové úrovni, například vypouští komentáře, vkládá soubory, nahrazuje jeden symbol za jiný atd. Překlad také probíhá na jednotlivých souborech odděleně. Výsledkem je již téměř hotový spustitelný binární kód, obsahuje ovšem odkazy na funkce a proměnné z ostatních přeložených souborů a také knihoven. Závěrečnou fází je linkování, kdy se z jednoho nebo několika takto "téměř přeložených" souborů vytvoří jeden spustitelný program.

Preprocesor

Celá řada jazyků (například Pascal, Java, ...) preprocesor vůbec nemá. Já osobně to považuji za chybu v návrhu těchto jazyků, která mohla vzniknout nejen autorovou neznalostí nebo ideologickou zaslepeností, ale někdy i prostým zděšením, k čemu všemu se v Céčku preprocesor používá. Pokud pracujete s překladačem gcc (na Linuxu obvykle ano), zkuste některý z příkladů předchozího dílu prohnat pouze preprocesorem bez dalších fází překladu.

gcc -E priklad.c

Díky příkazu preprocesoru #include <stdio.h>, který vkládá do našeho kódu standardní soubor stdio.h a tím zpřístupňuje některé funkce standardní knihovny, se na standardní výstup vyhrne přes 30 stránek kódu a až úplně nakonec následuje několik řádek našeho příkladu. Ještě mnohem horší je to u C++ a jeho standardních i nestandardních (napadá mě třeba Qt) knihoven. Díky množství #include kódu, který jen zpřístupňuje volání knihovních funkcí, trvá překlad i středně velkého projektu neúnosně dlouho, ačkoliv kód napsaný programátorem projektu není příliš rozsáhlý.

Dalším vážným problémem Céčka, který preprocesor jen zhoršuje, je ochrana identifikátorů. Snad každému zkušenějšímu C programátorovi se stalo, že si definoval makro preprocesoru, jehož název kolidoval s identifikátorem z nějaké knihovny.

Na druhou stranu preprocesor řadu věcí velmi usnadňuje. Vyzdvihl bych zejména podmíněný překlad. Díky němu lze poměrně jednoduše psát multiplatformní programy nebo psát ladící kód, který nebude v distribuční verzi přeloženého programu.

Vložení souboru

Soubor vložíme pomocí příkazu #include, který má dvě varianty.

#include <soubor.h>
#include "soubor.h"

V prvním případě se vezme soubor z adresáře se standardními hlavičkovými soubory (na Linuxu obvykle /usr/include), ve druhém pak z adresáře se zdrojovým kódem programu. V obou případech mohou jména souborů obsahovat relativní cestu, adresáře se oddělují obyčejným lomítkem a to i v DOSu a odvozených systémech, kde se jinak používá lomítko zpětné.

#include <sys/socket.h>
#include "../moje_knihovna/knihovna.h"

Vkládané soubory mají obvykle příponu .h, ale jde pouze o programátorskou konvenci, nikoli o vlastnost jazyka C. Obsah vkládaného souboru také není nijak omezen. Lze tedy například rozčlenit velký projekt do více zdrojových souborů a v jediném *.c souboru, který se bude překládat, mít jen několik #include příkazů. Takto se ovšem v C v praxi neprogramuje, vkládání souborů se obvykle používá pouze na zpřístupnění maker, typů, funkcí a proměnných. Podrobnosti si povíme v některém z dalších dílů, zatím jen stačí vědět, že známý příkaz preprocesoru #include <stdio.h>, kterým si zpřístupňujeme funkce puts a printf, je ve skutečnosti vložení souboru /usr/include/stdio.h.

Generování chyby

Překlad můžeme explicitně přerušit pomocí příkazu #error. Význam má zejména v souvislosti s podmíněným překladem, ale pro přepracované programátory má jistě význam i konstrukce

#error tady jsem skončil před dovolenou

Makro bez hodnoty

Makro bez parametrů definujeme příkazem #define

#define MAKRO

Definice platí do konce souboru, přesněji řečeno do konce souboru ve smyslu překladu nikoli preprocesoru. Pokud například makro definujeme v hlavičkovém souboru hlavicka.h a ten pak pomocí

#include "hlavicka.h"

vložíme do zdroj.c, bude definice platit i pro kód ze souboru zdroj.c a to od příkazu #include "hlavicka.h" dále, platná bude rovněž pro veškerý kód z případných následujících #include příkazů.

Na makro se můžeme dotázat pomocí příkazů #ifdef, #ifndef, #else a #endif, říká se tomu podmíněný překlad.

#define LADENI

 /*
  Tady je nějaký kód
*/

#ifdef LADENI
  printf("Proměnná i má hodnotu %i\n", i);
#endif

Pomocí jediné definice makra LADENI, kterou umístíme nejlépe do nějakého hlavičkového souboru, tak lze snadno zapnout ladící výpisy. V distribuční verzi programu pak definici makra zrušíme (tj. provedeme jedinou změnu na jednom místě) a program přestane ladící hlášky vypisovat.

Překladače navíc umožňují definovat makra externě mimo zdrojáky. V grafických vývojových prostředích lze obvykle vše naklikat, "správný" linuxový programátor použije parametr -D překladače gcc.

gcc program.c -DLADENI -o program

Pro přeložení distribuční verze zavolá standardně.

gcc program.c -o program

Tento způsob ovlivňování překladu je lepší než dotaz na ručně definované makro v *.h souboru, ušetříme si jím i tu jedinou změnu v jednom souboru.

Překladače definují (nebo nedefinují) celou řadu maker v závislosti na prostředí překladu. Z těch nejužitečnějších bych jmenoval unix, _WIN32 nebo __cplusplus, podrobnosti získáte v dokumentaci ke konkrétnímu překladači. Následující kód demonstruje užitečnost podmíněného překladu při multiplatformním programování. Na Windows pomocí API funkce z windows.h vyhodí dialog a všude jinde vypíše řetězec na standardní výstup.

#ifdef _WIN32
  MessageBox(NULL, "Ahoj světe!", "Zpráva", MB_OK);
#else
  puts("Ahoj světe");
#endif

Bez použití podmíněného překladu by na Linuxu překlad skončil s chybou kvůli neznámé funkci MessageBox a konstantě MB_OK.

Zda je program překládán jako C nebo jako C++ se zase můžeme zeptat pomocí makra __cplusplus. Díky částečné jednosměrné kompatibilitě lze obvykle C program přeložit i pomocí C++ překladače, pokud v něm nepoužíváme (např. jako identifikátory proměnných) klíčová slova C++ ani některé problematické konstrukce, které jsou v C++ zakázané.

#ifndef __cplusplus
  puts("Přeloženo jako čisté C");
#else
  puts("Přeloženo jako C++");
#endif

Makro s hodnotou

Makro může mít nějakou hodnotu, běžně se jako makra definují konstanty používané na více místech nebo pokud chceme mít jakési nastavení programu na jednom místě například v hlavičkovém souboru. Z hlediska vlastního překladu je makro konstanta a nikoli proměnná, takže lze makra použít i jako meze polí.

#define N 10

int a[N];

int main(void) {
  int i;

  for(i = 0; i < N; i++)
    a[i] = i;
  return 0;
}

Hodnotou makra může být prakticky cokoli, takže lze napsat i následující hrůzu:

#include <stdio.h>

#define KONEC return 0;
#define CYKLUS_PRES_I for(i = 0; i < N; i++)
#define RETEZEC "Ahoj světe"
#define NOVY_RADEK puts("");
#define N 10

int main(void) {
  int i;
  
  CYKLUS_PRES_I {
    printf(RETEZEC);
    NOVY_RADEK
  }
  KONEC
}

Hodnotu makra můžeme pomocí zpětného lomítka napsat i na více řádků.

#define ERR_STRING "Chyba 134\n" \
                   "syntaxe: prhlizec soubor.cfg url\n"\
                   "příklad: prohlizec /etc/prohlizec.cfg http://linuxsoft.cz"

Řídit překlad můžeme také pomocí #if a konstantního výrazu. Běžné komentáře v C mají tu nevýhodu, že je nelze zanořovat. Pokud tedy chceme dočasně zakomentovat kus kódu, který již obsahuje běžné komentáře, nelze použít

 /*
  int moje_funkce() {
    /* Vnořený komentář - chyba !!! */
    return 0;
  }
*/

Nic nám však nebrání použít #if.

#if 0
  /* Tak trochu jiný komentář... */
  int moje_funkce() {
    /* Vnořený komentář - OK */
    return 0;
  }
#endif

V konstantním výrazu v #if lze navíc použít i makra a také běžné operátory. Ve spolupráci s direktivou #elif a operátorem defined lze již napsat opravdu zajímavé věci. Ukážeme si to na příkladu.

Příklad pro dnešní díl

Při psaní větších projektů je třeba předem myslet na ladění. Náš příklad je velmi jednoduchý, a ladící kód proto působí dost nepřirozeně. Ve skutečných a složitých případech však může podobně opatrný přístup ušetřit spoustu práce při hledání chyb.

#include <stdio.h>

#define N 10

 /*

Tyto definice raději zadáme zvnějšku

#define LADIM
#define MALA 0
#define VELKA 1
#define UROVEN VELKA

*/

int a[N];

int main(void) {
  int i;
  
  for (i = 0; i <= N; i++) {
#ifdef LADIM
    if (i >= sizeof(a)/sizeof(int)) {
      printf("Pokus o přístup mimo pole na index %i\n", i);
      return 1;
    }
#if UROVEN==VELKA
    printf("Do pole a na index %i píšu %i\n", i, i);
#elif UROVEN==MALA
    putchar('.'); /* Aby bylo vidět, že se program nekousl */
#endif
#endif /* od #ifdef LADIM */
    a[i] = 1;
  }
#if defined LADIM && UROVEN==VELKA
  puts("Konec programu");
#endif
  return 0;
}

Zkuste si program přeložit třeba takhle:

gcc program.c -o program -DLADIM -DMALA=0 -DVELKA=1 -DUROVEN=VELKA

Pokud používáte jiný překladač a neumíte zadat makro zvnějšku, odkomentujte definici maker ve zdrojovém kódu.

Pokračování příště

I v dalším dílu se zaměříme na preprocesor. Ukážeme si, jak se píší makra s parametry.

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

13.9.2017 8:00 /František Kučera

Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt – tentokrát netradičně v pondělí: 18. září od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).


Přidat komentář

3.9.2017 20:45 /Redakce Linuxsoft.cz
PR: Dne 21. září 2017 proběhne v Praze konference "Mobilní řešení pro business". Hlavní tématy konference budou: nejnovější trendy v oblasti mobilních řešení pro firmy, efektivní využití mobilních zařízení, bezpečnostní rizika a řešení pro jejich omezení, správa mobilních zařízení ve firmách a další.
Přidat komentář

15.5.2017 23:50 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 18. května od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.5.2017 16:42 /Honza Javorek
PyCon CZ, česká konference o programovacím jazyce Python, se po dvou úspěšných ročnících v Brně bude letos konat v Praze, a to 8. až 10. června. Na konferenci letos zavítá např. i Armin Ronacher, známý především jako autor frameworku Flask, šablon Jinja2/Twig, a dalších projektů. Těšit se můžete na přednášky o datové analytice, tvorbě webu, testování, tvorbě API, učení a mentorování programování, přednášky o rozvoji komunity, o použití Pythonu ve vědě nebo k ovládání nejrůznějších zařízení (MicroPython). Na vlastní prsty si můžete na workshopech vyzkoušet postavit Pythonem ovládaného robota, naučit se učit šestileté děti programovat, efektivně testovat nebo si v Pythonu pohrát s kartografickým materiálem. Kupujte lístky, dokud jsou.
Přidat komentář

2.5.2017 9:20 /Eva Rázgová
Putovní konference československé Drupal komunity "DrupalCamp Československo" se tentokrát koná 27. 5.2017 na VUT FIT v Brně. Můžete načerpat a vyměnit si zkušenosti z oblasti Drupalu 7 a 8, UX, SEO, managementu týmového vývoje, využití Dockeru pro Drupal a dalších. Vítáni jsou nováčci i experti. Akci pořádají Slovenská Drupal Asociácia a česká Asociace pro Drupal. Registrace na webu .
Přidat komentář

1.5.2017 20:31 /Pavel `Goldenfish' Kysilka
PR: 25.5.2017 proběhne v Praze konference na téma Firemní informační systémy. Hlavními tématy jsou: Informační systémy s vlastní inteligencí, efektivní práce s dokumenty, mobilní přístup k datům nebo využívání cloudu.
Přidat komentář

15.4.2017 15:20 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě IoT a radiokomunikace? Přijď na sraz spolku OpenAlt, který se bude konat ve středu 19. dubna od 18:30 v Šenkovně (Sokolská 60, Praha 2).
Přidat komentář

5.3.2017 19:12 /Redakce Linuxsoft.cz
PR: 23. března proběhne v Praze konferenci na téma Cloud computing v praxi. Hlavními tématy jsou: Nejžhavější trendy v oblasti cloudu a cloudových řešení, Moderní cloudové služby, Infrastruktura současných cloudů, Efektivní využití cloudu, Nástrahy cloudových řešení a jak se jim vyhnout.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

18.9.2017 14:37 / Rojas
high security vault

15.9.2017 7:33 / Wilson
new zealand childcare jobs

31.8.2017 12:11 / Jaromir Obr
Re: ukůládání dat ze souboru

30.7.2017 11:12 / Jaromir Obr
Národní znaky

27.7.2017 12:24 / Jaromir Obr
Cteni/zapis

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2017) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze