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 63725×

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ů

18.9.2018 23:30 /František Kučera

Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.


Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

18.6.2018 0:43 /František Kučera
Červnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 21. 6. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: F-Droid, aneb svobodný software do vašeho mobilu. Kromě toho budou k vidění i vývojové desky HiFive1 se svobodným/otevřeným čipem RISC-V.
Přidat komentář

23.5.2018 20:55 /Ondřej Čečák
Od pátku 25.5. proběhne na Fakultě informačních technologií ČVUT v Praze openSUSE Conference. Můžete se těšit na spostu zajímavých přednášek, workshopů a také na Release Party nového openSUSE leap 15.0. V na stejném místě proběhne v sobotu 26.5. i seminář o bezpečnosti CryptoFest.
Přidat komentář

20.5.2018 17:45 /Redakce Linuxsoft.cz
Ve čtvrtek 31. května 2018 připravuje webový magazín BusinessIT ve spolupráci s Best Online Média s.r.o. pátý ročník odborné konference Firemní informační systémy 2018. Akce proběhne v kongresovém centru Vavruška (palác Charitas), Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 15 hod. odpoledne. Konference je zaměřena na efektivní využití firemních informačních systémů a na to, jak plně využít jejich potenciál. Podrobnější informace na webových stránkách konfrence.
Přidat komentář

14.5.2018 7:28 /František Kučera
Květnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 17. 5. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: Audio – zvuk v GNU/Linuxu.
Přidat komentář

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

> Poslední diskuze

20.9.2018 10:04 / Jan Ober
Jaký kurz a software by jste doporučili pro začínajcího kodéra?

20.9.2018 10:00 / Jan Ober
Re: Gimp

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

Více ...

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