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 68885×
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
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
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
|
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|

Vyhledávání software

Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 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 umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
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ář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|