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.
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 ).
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ý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 .
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.
C programovací jazyk | |
---|---|
Kompilátory |
|
Knihovny | |
Zvláštnosti | |
Někteří potomci | |
C a další jazyky |
|
Kategorie:C programovací jazyk |