Hlavičkový soubor

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 28. února 2016; kontroly vyžadují 20 úprav .

V programování je hlavičkový soubor ( anglicky  header file ) nebo zahrnutý soubor  soubor, jehož obsah je automaticky přidán preprocesorem do zdrojového textu v místě, kde se nachází nějaká směrnice ( {$I file.inc}v Pascalu , #include <file.h>v C).

V programovacích jazycích C a C++ jsou hlavičkové soubory primárním způsobem, jak do programu zahrnout datové typy , struktury, prototypy funkcí , výčtové typy a makra používaná v jiném modulu. Výchozí přípona je .h ; někdy se pro hlavičkové soubory C++ používá přípona .hpp .

Aby se zabránilo opětovnému zahrnutí stejného kódu, používají se směrnice #ifndef, #define, #endif.

Hlavičkový soubor může obecně obsahovat libovolné konstrukce programovacího jazyka , ale v praxi se spustitelný kód (s výjimkou inline funkcí v C++ ) neumisťuje do hlavičkových souborů. Například identifikátory , které musí být deklarovány ve více než jednom souboru, lze pohodlně popsat v souboru záhlaví a poté zahrnout podle potřeby. Modularita funguje stejným způsobem ve většině assemblerů .

Tradičně hlavičkové soubory deklarují standardní knihovní funkce C a C++ .

V jiných jazycích (například v Pascalu ) se používá vyvinutý systém modulů. Ale i v nich mají hlavičkové soubory určitou hodnotu. Faktem je, že dva soubory (hlavní a hlavičkový) jsou sloučeny do jedné překladové jednotky , a proto hlavičkový soubor může obsahovat direktivy preprocesoru , nedokončené syntaktické konstrukce.

Schůzka

V moderních programovacích jazycích se programy skládají z modulů , které se kompilují samostatně. V tomto ohledu vyvstává otázka: jak naznačit, že podprogram nebo proměnná X je definována v modulu Y? Existuje několik řešení pro toto, v C se to aplikuje.

V jedné z kompilačních jednotek (tj. с-soubor) je popsána funkce, například:

int přidat ( int a , int b ) { vrátit a + b ; }

Aby bylo možné na něj odkazovat z jiných kompilačních jednotek, je nutné jej deklarovat pomocí prototypu funkce , tj.

int přidat ( int , int ); int triple ( int x ) { return add ( x , add ( x , x )); }

Taková deklarace však vyžaduje, aby programátor poskytl deklaraci funkce pro addna dvou místech – v souboru obsahujícím její implementaci a v souboru, ve kterém je použita. Pokud se změní definice funkce, programátor musí pamatovat na aktualizaci všech prototypů používaných v programu.

Soubor záhlaví je jedním z řešení tohoto problému. Hlavičkový soubor modulu deklaruje každou funkci , objekt a datový typ , který je součástí vyvolávacího rozhraní modulu – například v tomto případě může hlavičkový soubor obsahovat pouze deklaraci funkce add. Každý zdrojový soubor, který odkazuje na funkci, addmusí používat direktivu #includek zahrnutí souboru záhlaví:

/* Soubor triple.c */ #include "add.h" int triple ( int x ) { return add ( x , add ( x , x )); }

Seznamy inicializovaných konstant v hlavičkovém souboru volí preprocesor , aby byly nahrazeny hodnotou těchto konstant v obsaženém souboru. Zahrnuté funkce záhlaví souboru jsou orámovány direktivami makroochrany preprocesoru, aby se předešlo jejich duplikaci v souboru include (taková situace může nastat u dědičnosti třídy nebo souboru ):

/* File add.h */ #ifndef ADD_H #define ADD_H int add ( int , int ); #endif /* ADD_H */

Kromě designu #ifndef - #endifse někdy používá nestandardní #pragma once:

/* File add.h */ #pragma jednou int přidat ( int , int );

Hlavičkové soubory usnadňují údržbu - když se definice změní, stačí aktualizovat pouze jednu deklaraci (ta v hlavičkovém souboru) . Do zdrojového souboru můžete také zahrnout hlavičkový soubor obsahující definice použité ve zdrojových souborech. To umožňuje kompilátoru zkontrolovat, zda deklarace v h-file odpovídá definici v c-file:

/* Soubor add.c */ #include "add.h" int přidat ( int a , int b ) { vrátit a + b ; }

Soubory záhlaví se obvykle používají pouze k jasnějšímu definování rozhraní a obvykle obsahují komentáře vysvětlující, jak lze použít komponenty deklarované v souboru. Ve výše uvedeném příkladu jsou použité podprogramy rozděleny do samostatných zdrojových souborů, které je nutné zkompilovat samostatně (výjimkou v jazycích C a C++ jsou inline funkce , které jsou často součástí hlavičkového souboru, protože ve většině případů v případech není možné správně rozšířit inline funkci bez volání jejich definice v době kompilace ).

Porovnání s přímým získáváním záhlaví z kompilovaného modulu

Alternativou k hlavičkovým souborům je získat informace o deklarovaných typech, funkcích atd. přímo z kompilovaného modulu. Pascal , Java a další to dělají .

Výhody

Výhodou hlavičkových souborů je především zjednodušení kompilátoru: bez hlavičkových souborů provádějí kompilátor a linker stejnou práci při kontrole, zda modul obsahuje Yzkompilovanou funkci X.

Pokud je modul napsán správně, podmíněná kompilace může zakázat některé jeho funkce. V tomto případě například odmítáme propojit obrovskou knihovnu STL s programem :

// unit.h #ifndef __UNIT_H__ #define __UNIT_H__ #ifndef UNIT_STL_UNUSED #include <iostream> void dump ( std :: ostream & os ); void dump () { dump ( std :: cout ); } #endif void run (); #endif // main.cpp #define UNIT_STL_UNUSED #include "unit.h" int main () { běh (); návrat 0 ; }

Pokud je modul distribuován již zkompilovaný (knihovna), hlavičkový soubor bude zároveň dokumentací o používání modulu.

Pokud programátor opraví implementaci funkce v c-souboru, aniž by se dotkl hlavičky, nezpůsobí to kaskádovou rekompilaci všech modulů, které tuto hlavičku používají.

Hlavičkový soubor umožňuje specifikovat něco, co nelze specifikovat pomocí modulů - substituce s #define, direktivy kompilátoru , nedokončené syntaktické konstrukce...

Zjednodušuje interakci mezi moduly napsanými v různých jazycích. Kompilátor a linker se vůbec nestarají o to, zda je volaný modul napsán ve stejném jazyce nebo v jiném. Různé jazyky navíc mohou kompilovat své moduly do stejných objektových souborů – v tomto případě získáte jeden linker pro několik jazyků. Podobně je snadné vytvořit knihovnu, kterou se uživatel rozhodne zahrnout do projektu jako soubory CPP, uložené předkompilované a propojené staticky nebo propojené jako DLL .

Nevýhody

Hlavičkové soubory jsou mnohem pomalejší - pro kompilaci 10 c-souborů, každý s připojeným dlouhým -souborem , musí hkompilátor projít hlavičku 10krát. K řešení tohoto problému mnoho kompilátorů používá předkompilovaný .

Hlavičkové soubory spolu s některými objekty jazyka C++ ( konstanty , inline-funkce, šablony , static-proměnné) tvoří těžké konstrukce.

Programátor musí synchronně měnit hlavičky funkcí na dvou místech. Pokud změnil c-file a zapomněl udělat totéž s h-file, linker vydá vágní chybovou zprávu bez čísla řádku. To je zvláště patrné v C++ , kde stejná funkce může mít jinou sadu argumentů a kontrola na úrovni kompilátoru nefunguje. Pokud by programátor omylem nechal konstrukci v h-souboru nedokončenou, chyba by byla v úplně jiném c-nebo h-souboru.

Projekty z jazyků rodiny C se vyznačují složitými schématy sestavování projektů. Ostatně (alespoň ve standardním C ++) je potřeba do projektu zahrnout knihovnu – ať už ve formě souborů CPP nebo v kompilované podobě. I když (například ve Visual C++) pro to existují direktivy preprocesoru, knihovna se bude muset sestavit.

Viz také

Odkazy

Literatura

  • Podbelsky V. V. Kapitola 8. Nástroje preprocesoru // jazyk C++ / rec. Dadaev Yu. G. - 4. - M. : Finance and Statistics , 2003. - S. 263-280. — 560 str. - ISBN 5-279-02204-7 , MDT 004.438Si (075.8) LBC 32.973.26-018 1ya173.