LINUXSOFT.cz Přeskoč levou lištu

ARCHIV



   

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

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ů

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 ...

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