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

> C/C++ (16) - Hlavičkové soubory

Dnes probereme hlavičkové soubory a metodiku práce při psaní projektů z více zdrojových souborů. Příkaz #include <stdio.h> už pro nás přestane být jen vložením tajemného souboru, který nějakým neznámým způsobem zpřístupní některé funkce ze standardní knihovny.

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

Hlavičkové soubory

V minulých dílech jsme si ukázali některé konstrukce jazyka, které umožní sestavit program z více zdrojových souborů. Jde zejména o hlavičky funkcí a deklarace proměnných pomocí klíčového slova extern, dále makra preprocesoru určená ke globálnímu použití a příkaz #include. Zatím jsme příliš nepřemýšleli kam nejlépe příslušnou část kódu umístit. Pokud jsme v souboru main.c užívali funkci z funkce.c, napsali jsme prostě na začátek main.c její hlavičku. V případě globálních proměnných z funkce.c jsme stejným způsobem přidali do main.c jejich extern deklaraci. Tímto způsobem se v praxi neprogramuje. Bylo by jistě nepříjemné pro každou funkci opisovat hlavičku tolikrát, v kolika souborech je použita.

Při nejčastějším způsobu práce odpovídá každému *.c souboru, který poskytuje nějaké funkce a globální proměnné, jeden *.h soubor. Název se zpravidla liší pouze příponou. V tomto *.h souboru jsou hlavičky všech funkcí určených k použití z ostatních *.c souborů, dále extern deklarace globálních proměnných a makra preprocesoru, která nějak souvisí s obsahem příslušného *.c souboru. Hlavičkový *.h soubor obsahuje i definice uživatelských typů, ale to ještě neumíme. Tento soubor se pak pomocí příkazu #include vkládá na začátek všech *.c nebo i jiných *.h souborů, které jej potřebují.

Jednoduchý příklad se dvěma *.c soubory by mohl vypadat asi takhle:

funkce.h

void funkce(void);

funkce.c

void funkce(void) {
  /* ... */
}

main.c

#include "funkce.h"

int main(void) {
  funkce();
  return 0;
}

Všimněte si, že souboru main.c v našem příkladu neodpovídá žádný main.h, neboť v main.c neposkytujeme žádné funkce ani proměnné k použití z jiných souborů.

Problémy mohou vznikat při cyklické nebo jinak složité závislosti. Mějme projekt ze tří *.c souborů: main.c, funkce.c a rutiny.c, main.c volá funkce z obou zbývajících a funkce.c a rutiny.c jsou rovněž na sobě vzájemně závislé. V tom případě vytvoříme hlavičkové soubory funkce.h a rutiny.h. Všechny tři *.c soubory můžeme zahájit příkazy

#include "funkce.h"
#include "rutiny.h"

Zatím bude vše fungovat. Horší to bude, pokud vznikne závislost i mezi *.h soubory. To se může snadno stát, pokud v funkce.h definujeme makro, které používá jiné makro z rutiny.h. V tom případě umístíme i do funkce.h příkaz

#include "rutiny.h"

Bohužel v *.c souborech bude rutiny.h inkludován celkem dvakrát, jednou přímo a jednou prostřednictvím funkce.h. To se nebude líbit překladači. V takto jednoduchém projektu z několika souborů lze vždy problém nějak obejít, inkludovat jen některé hlavičkové soubory nebo naopak inkludovat všechny v pevném pořadí a zrušit #include příkaz ve funkce.h atd., ale v praktických složitějších projektech podobné řešení často nelze provést. Je proto třeba nějak zajistit, aby se obsah *.h souboru vkládal jen jednou a to i v případě, že je příkaz #include zavolán (přímo nebo zprostředkovaně) vícekrát. Řešení není příliš obtížné:

rutiny.h

#ifndef _RUTINY_H
#define _RUTINY_H

extern int globalni_promenna;
void rutiny(void);

#endif

Takto se skutečně v praxi programuje. Soubor se vkládá pouze pokud není definováno makro s charakteristickým jménem, v opačném případě vloží preprocesor příkazem #include nanejvýš pár prázdných řádek. Pokud se obsah souboru vkládá, je prvním příkazem definice výše zmíněného makra, které zabrání opakovanému vložení. Podobným způsobem je ošetřeno určitě alespoň 99% hlavičkových souborů ze skutečných projektů, zcela jednotná není pouze metodika pojmenování makra, lišit se mohou například množstvím a umístěním podtržítek a setkáme se i s makry jako rutinyH a podobně.

Při tomto způsobu práce lze již s úspěchem psát velké projekty s vysokým stupněm vzájemné závislosti jednotlivých částí. Zdrojové *.c soubory na sobě záviset (přes volání funkce nebo použití proměnné) i cyklicky, závislost *.h souborů (použití makra nebo uživatelského typu, příkaz #include) cyklus obsahovat nesmí. Je běžné, že *.c soubor inkluduje větší množství *.h souborů stejného projektu. Nikdy by nemělo být podstatné pořadí #include příkazů a nemělo by ani vadit inkludování *.h souboru, které se nevyužije.

Popsaný způsob, kdy jednomu *.c souboru odpovídá právě jeden hlavičkový soubor, je určitě nečastější, ale setkáme se i s rozdělením funkcí, proměnných, maker a typů, které se všechny týkají jednoho *.c souboru, do více *.h, například funkce zvlášť, proměnné zvlášť atd. Poměrně běžný je i opačný přístup, kdy se naopak vše uloží do jediného hlavičkového souboru, který tak pokrývá nějaký logický celek složený z více *.c souborů. Pokud projekt obsahuje podmíněný překlad závislý na definici makra (například přítomnost ladícího kódu, platforma produktu, ...) a nechceme tuto definici předávat jako parametr překladači, je vhodné všechny volby umístit do jediného hlavičkového souboru. Ten se pak bude pomocí #include vkládat do všech ostatních souborů, které obsahují podmíněný překlad.

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

Ukážeme si kompletní zdrojový kód projektu ze dvou *.c souborů a jednoho *.h. Ve funkce.c je funkce, která podle jednoduchého vzorečku sečte n přirozených čísel, a globální proměnná. Ve funkce.h je hlavička funkce a deklarace proměnné s extern. Z main.c se jen volá funkce a vypíše hodnota proměnné.

funkce.h

#ifndef _FUNKCE_H
#define _FUNKCE_H

extern int pocet_volani;

/* vrací 1 + 2 + 3 + ... + n */
int suman(int n);
#endif

funkce.c

int pocet_volani = 0;

int suman(int n) {
  pocet_volani++;
  return (n * (n + 1)) / 2;
}

main.c

#include <stdio.h>
#include "funkce.h"

int main(void) {
  printf("1 + 2 + 3 + 4 + 5 = %i\n", suman(5));
  printf("počet volání suman() = %i\n", pocet_volani);
  return 0;
}

Příklad přeložíme nejjednodušeji

gcc main.c funkce.c -o priklad

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

V příštím dílu se naučíme překládat s pomocí příkazu make. To je poslední věc, kterou zatím stále děláme jinak než ve skutečných projektech.

Verze pro tisk

pridej.cz

 

DISKUZE

C/C++ 17.3.2005 21:29 jan
  L Re: C/C++ 18.3.2005 07:37 Jan Němec
    L Re: C/C++ 19.3.2009 12:46 Vojtěch 'Malajda' Malášek
      L Re: C/C++ 19.3.2009 15:50 Aleš Hakl




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