I programmering er en header-fil ( engelsk header-fil ) eller en inkluderet fil en fil, hvis indhold automatisk tilføjes af præprocessoren til kildeteksten på det sted, hvor et eller andet direktiv er placeret ( {$I file.inc}i Pascal , #include <file.h>i C).
I programmeringssprogene C og C++ er header-filer den primære måde at inkludere datatyper , strukturer, funktionsprototyper , opregnede typer og makroer , der bruges i et andet modul i et program. Standardudvidelsen er .h ; _ nogle gange bruges .hpp- udvidelsen til C++ header-filer .
For at undgå genindsættelse af den samme kode, bruges direktiver #ifndef, #define, #endif.
Header-filen kan generelt indeholde alle programmeringssprogskonstruktioner , men i praksis placeres eksekverbar kode (med undtagelse af inline-funktioner i C++ ) ikke i header-filer. For eksempel kan identifikatorer , der skal erklæres i mere end én fil, bekvemt beskrives i en header-fil og derefter inkluderes efter behov. Modularitet fungerer på samme måde i de fleste montører .
Traditionelt erklærer header-filer C- og C++- standardbiblioteksfunktioner .
På andre sprog (for eksempel i Pascal ) bruges et udviklet system af moduler. Men selv i dem har header-filer en vis værdi. Faktum er, at to filer (main og header) er flettet sammen til en oversættelsesenhed , og derfor kan header-filen indeholde præprocessor-direktiver , ufærdige syntaktiske konstruktioner.
I moderne programmeringssprog består programmer af moduler , der er kompileret separat. I denne forbindelse opstår spørgsmålet: hvordan angiver man, at en subrutine eller en variabel X er defineret i et modul Y? Det er der flere løsninger på, i C er det anvendt.
I en af kompileringsenhederne (dvs. с-fil) beskrives en funktion, for eksempel:
int add ( int a , int b ) { returnere a + b ; }For at kunne henvise til det fra andre kompileringsenheder, er det nødvendigt at deklarere det ved hjælp af en funktionsprototype , dvs.
int tilføje ( int , int ); int tredobbelt ( int x ) { return add ( x , add ( x , x )); }En sådan erklæring kræver dog, at programmøren afgiver en erklæring om funktionen for addto steder - i filen, der indeholder dens implementering, og i den fil, hvori den bruges. Hvis en funktionsdefinition ændres, skal programmøren huske at opdatere alle de prototyper, der bruges i programmet.
Header-filen er en løsning på dette problem. Et moduls header-fil erklærer hver funktion , objekt og datatype, der er en del af modulets påkaldelsesgrænseflade - for eksempel, i dette tilfælde kan header-filen kun indeholde en funktionserklæring add. Hver kildefil, der refererer til en funktion add, skal bruge et direktiv #includetil at inkludere en overskriftsfil:
/* Fil triple.c */ #inkluder "add.h" int tredobbelt ( int x ) { return add ( x , add ( x , x )); }Listerne over initialiserede konstanter i header-filen vælges af præprocessoren til at blive erstattet af værdien af disse konstanter i den inkluderede fil. Inkluderede header-filfunktioner er indrammet af præprocessor- makrobeskyttelsesdirektiver for at undgå deres duplikering i den inkluderende fil (en sådan situation kan forekomme med klasse- eller filarv ):
/* Fil add.h */ #ifndef ADD_H #define ADD_H int add ( int , int ); #endif /* ADD_H */Ud over designet #ifndef - #endifbruges nogle gange en ikke-standard #pragma once:
/* Fil add.h */ #pragma én gang int tilføje ( int , int );Header-filer gør det nemmere at vedligeholde - når en definition ændres, skal kun én erklæring (den i header-filen) opdateres . Du kan også inkludere en header-fil, der indeholder definitionerne, der bruges i kildefilerne, til kildefilen. Dette giver compileren mulighed for at kontrollere, om erklæringen i h-filen matcher definitionen i c-filen:
/* Fil add.c */ #inkluder "add.h" int add ( int a , int b ) { returnere a + b ; }Typisk bruges header-filer kun til at definere grænsefladen mere tydeligt og indeholder normalt kommentarer, der forklarer, hvordan komponenterne , der er erklæret i filen, kan bruges. I ovenstående eksempel er de anvendte underrutiner opdelt i separate kildefiler, der skal kompileres separat (en undtagelse i C- og C++-sprogene er inline-funktioner , som ofte er inkluderet i header-filen på grund af det faktum, at i de fleste brug tilfælde er det ikke muligt at udvide den inline-funktion korrekt uden kald til deres definition på kompileringstidspunktet ).
Et alternativ til header-filer er at få information om deklarerede typer, funktioner osv. direkte fra det kompilerede modul. Pascal , Java og andre gør dette .
Fordelen ved header-filer er primært at forenkle compileren: uden header-filer udfører compileren og linkeren det samme arbejde med at kontrollere, om et modul indeholder en Ykompileret funktion X.
Hvis et modul er skrevet korrekt, kan betinget kompilering deaktivere noget af dets funktionalitet. For eksempel nægter vi i dette tilfælde at linke et stort STL -bibliotek til programmet :
// unit.h #ifndef __UNIT_H__ #define __UNIT_H__ #ifndef UNIT_STL_UNUSED #inkluder < iostream> void dump ( std :: ostream & os ); void dump () { dump ( std :: cout ); } #Afslut Hvis void run (); #Afslut Hvis // main.cpp #define UNIT_STL_UNUSED #inkluder " unit.h" int main () { køre (); returnere 0 ; }Hvis modulet er distribueret allerede kompileret (bibliotek), vil header-filen samtidig være dokumentation for brug af modulet.
Hvis programmøren retter implementeringen af en funktion i en c-fil uden at røre headeren, vil dette ikke forårsage en kaskade-rekompilering af alle moduler, der bruger denne header.
Header-filen giver dig mulighed for at specificere noget, der ikke kan specificeres ved hjælp af moduler - substitutioner med #define, compiler-direktiver , ufærdige syntaktiske konstruktioner ...
Forenkler interaktionen mellem moduler skrevet på forskellige sprog. Compileren og linkeren er overhovedet ligeglad med, om det kaldte modul er skrevet på samme sprog eller på et andet. Derudover kan forskellige sprog kompilere deres moduler til de samme objektfiler - i dette tilfælde får du en linker til flere sprog. På samme måde er det nemt at lave et bibliotek, som brugeren vælger at inkludere i et projekt som CPP-filer, gemt præ-kompileret og linket statisk eller linket som en DLL .
Header-filer er meget langsommere - for at kompilere 10 c-filer, hver med en lang -fil vedhæftet , skal hcompileren gå gennem headeren 10 gange. For at håndtere dette problem bruger mange compilere precompiled .
Header-filer sammen med nogle objekter i C++-sproget ( konstanter , inline-funktioner, skabeloner , static-variabler) danner tunge konstruktioner.
Programmøren skal synkront ændre funktionsoverskrifter to steder. Hvis han ændrede c-filen og glemte at gøre det samme med h-filen, vil linkeren give en vag fejlmeddelelse uden linjenummer. Dette er især bemærkelsesværdigt i C++ , hvor den samme funktion kan have et andet sæt af argumenter , og kontrollen på compilerniveau ikke virker. Hvis en programmør ved et uheld efterlod en konstruktion i en h-fil ufærdig, ville fejlen være i en helt anden c-eller h-fil.
Projekter fra sprog i C-familien er kendetegnet ved komplekse projektsamlingsordninger. Når alt kommer til alt (i hvert fald i standard C++), skal du inkludere et bibliotek i projektet - enten i form af CPP-filer eller i en kompileret form. Selvom der (for eksempel i Visual C++) er præprocessor-direktiver for dette, skal biblioteket stadig bygges.
C programmeringssprog | |
---|---|
Kompilere |
|
Biblioteker | |
Ejendommeligheder | |
Nogle efterkommere | |
C og andre sprog |
|
Kategori:C programmeringssprog |