Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln handlar om att skapa och importera rubrikenheter med Visual Studio 2022. Information om hur du importerar C++-standardbibliotekshuvuden som rubrikenheter finns i Genomgång: Importera STL-bibliotek som rubrikenheter. Ett ännu snabbare och mer robust sätt att importera standardbiblioteket finns i Självstudie: Importera C++-standardbiblioteket med hjälp av moduler.
Rubrikenheter är det rekommenderade alternativet till förkompilerade huvudfiler (PCH). Rubrikenheter är enklare att konfigurera och använda, är betydligt mindre på disken, ger liknande prestandafördelar och är mer flexibla än en delad PCH.
Om du vill kontrastera rubrikenheter med andra sätt att inkludera funktioner i dina program kan du läsa Jämför rubrikenheter, moduler och förkompilerade rubriker.
Förutsättningar
Om du vill använda rubrikenheter behöver du Visual Studio 2019 16.10 eller senare.
Vad är en rubrikenhet?
En rubrikenhet är en binär representation av en rubrikfil. En rubrikenhet slutar med ett .ifc tillägg. Samma format används för namngivna moduler.
En viktig skillnad mellan en rubrikenhet och en rubrikfil är att en rubrikenhet inte påverkas av makrodefinitioner utanför rubrikenheten. Det innebär att du inte kan definiera en förprocessorsymbol som gör att rubrikenheten beter sig annorlunda. När du importerar rubrikenheten är huvudenheten redan kompilerad. Det skiljer sig från hur en #include fil behandlas. En inkluderad fil kan påverkas av en makrodefinition utanför huvudfilen eftersom huvudfilen går igenom förprocessorn när du kompilerar källfilen som innehåller den.
Rubrikenheter kan importeras i valfri ordning, vilket inte gäller för huvudfiler. Rubrikfilordningen är viktig eftersom makrodefinitioner som definierats i en rubrikfil kan påverka en efterföljande rubrikfil. Makrodefinitioner i en rubrikenhet kan inte påverka en annan rubrikenhet.
Allt som visas från en rubrikfil visas också från en rubrikenhet, inklusive makron som definierats i rubrikenheten.
En rubrikfil måste översättas till en rubrikenhet innan den kan importeras. En fördel med rubrikenheter jämfört med förkompilerade huvudfiler (PCH) är att de kan användas i distribuerade versioner. Så länge du kompilerar .ifc och programmet som importerar det med samma kompilator och siktar på samma plattform och arkitektur, kan en headerenhet som produceras på en dator användas på en annan. Till skillnad från en PCH, när en rubrikenhet ändras, återskapas bara den och vad som är beroende av den. Rubrikenheter kan vara upp till tio gånger mindre än en .pch.
Rubrikenheter medför färre begränsningar för de likheter som krävs för kombinationer av kompilatorväxlar som används för att skapa rubrikenheten och för att kompilera koden som använder den än en PCH. Vissa växelkombinationer och makrodefinitioner kan dock skapa överträdelser av en definitionsregel (ODR) mellan olika översättningsenheter.
Slutligen är enheterna för rubriker mer flexibla än en PCH. Med en PCH kan du inte välja att bara ta in en av rubrikerna i PCH – kompilatorn bearbetar dem alla. Med rubrikenheter, även när du kompilerar dem till ett statiskt bibliotek, tar du bara med innehållet i rubrikenheten som du importerar till ditt program.
Rubrikenheter är ett steg mellan huvudfiler och C++20-moduler. De ger några av fördelarna med moduler. De är mer robusta eftersom externa makrodefinitioner inte påverkar dem , så du kan importera dem i valfri ordning. Kompilatorn kan bearbeta dem snabbare än huvudfiler. Men rubrikenheter har inte alla fördelar med moduler eftersom rubrikenheter exponerar makrona som definierats i dem (moduler gör det inte). Till skillnad från moduler finns det inget sätt att dölja privat implementering i en rubrikenhet. För att ange privat implementering med huvudfiler används olika tekniker som att lägga till inledande understreck i namn eller placera saker i ett implementeringsnamnområde. En modul exponerar inte privat implementering i någon form, så du behöver inte göra det.
Överväg att ersätta dina förkompilerade rubriker med rubrikenheter. Du får samma hastighetsfördel, men även med andra fördelar med kodhygien och flexibilitet.
Sätt att kompilera en rubrikenhet
Det finns flera sätt att kompilera en fil till en rubrikenhet:
Skapa ett projekt för delad rubrikenhet. Vi rekommenderar den här metoden eftersom den ger mer kontroll över organisationen och återanvändning av de importerade rubrikenheterna. Skapa ett statiskt biblioteksprojekt som innehåller de rubrikenheter som du vill använda och referera sedan till det för att importera rubrikenheterna. En genomgång av den här metoden finns i Skapa ett statiskt bibliotekprojekt för header-enheter.
Välj enskilda filer som ska översättas till rubrikenheter. Den här metoden ger dig fil-för-fil-kontroll över vad som behandlas som en rubrikenhet. Det är också användbart när du måste kompilera en fil som en rubrikenhet som, eftersom den inte har standardtillägget (
.ixx,.cppm,.h,.hpp), normalt inte kompileras till en rubrikenhet. Den här metoden visas i den här genomgången. Information om hur du kommer igång finns i Metod 1: Översätta en specifik fil till en rubrikenhet.Sök automatiskt efter och skapa huvudenheter. Den här metoden är bekväm, men passar bäst för mindre projekt eftersom den inte garanterar optimal byggprestanda. Mer information om den här metoden finns i Metod 2: Sök automatiskt efter rubrikenheter.
Som du nämnde i introduktionen kan du skapa och importera STL-huvudfiler som rubrikenheter och automatiskt behandla
#includeSTL-bibliotekshuvuden somimportutan att skriva om koden. Om du vill se hur går du till Genomgång: Importera STL-bibliotek som rubrikenheter.
Metod 1: Översätta en specifik fil till en rubrikenhet
Det här avsnittet visar hur du väljer en specifik fil som ska översättas till en rubrikenhet. Kompilera en rubrikfil som en rubrikenhet med hjälp av följande steg i Visual Studio:
Skapa ett nytt C++-konsolappprojekt.
Ersätt källfilinnehållet på följande sätt:
#include "Pythagorean.h" int main() { PrintPythagoreanTriple(2,3); return 0; }Lägg till en rubrikfil med namnet
Pythagorean.hoch ersätt dess innehåll med den här koden:#ifndef PYTHAGOREAN #define PYTHAGOREAN #include <iostream> inline void PrintPythagoreanTriple(int a, int b) { std::cout << "Pythagorean triple a:" << a << " b:" << b << " c:" << a*a + b*b << std::endl; } #endif
Ange projektegenskaper
Om du vill aktivera rubrikenheter anger du först C++ Language Standard till /std:c++20 eller senare med följande steg:
- Högerklicka på projektnamnet i Solution Explorer och välj Egenskaper.
- I den vänstra rutan i fönstret projektegenskapssidor väljer du Konfigurationsegenskaper>Allmänt.
- I listrutan C++ Language Standard väljer du ISO C++20 Standard (/std:c++20) eller senare. Välj Ok för att stänga dialogrutan.
Kompilera rubrikfilen som en rubrikenhet:
I Solution Explorer väljer du den fil som du vill kompilera som en rubrikenhet (i det här fallet
Pythagorean.h). Högerklicka på filen och välj Egenskaper.Ange listrutan Konfigurationsegenskaper>allmän>objekttyp till C/C++-kompilator och välj Ok.
När du senare i denna genomgång bygger det här projektet kommer Pythagorean.h att översättas till en rubrikenhet. Den översätts till en rubrikenhet eftersom objekttypen för den här huvudfilen är inställd på C/C++-kompilatorn, och eftersom standardåtgärden för .h och .hpp filer som anges på det här sättet är att översätta filen till en rubrikenhet.
Anmärkning
Detta krävs inte för den här genomgången, men den tillhandahålls för din information. Om du vill kompilera en fil som en headerenhet som inte har ett standardheaderrenhet filnamnstillägg, som till exempel .cpp, anger du Konfigurationsegenskaper>C/C++>Avancerad>Kompilering SomKompilering som C++ Headerenhet (/exportHeader):
Ändra koden för att importera rubrikenheten
I källfilen för exempelprojektet ändrar du
#include "Pythagorean.h"tillimport "Pythagorean.h";Glöm inte det avslutande semikolonet. Det krävs förimportinstruktioner. Eftersom det är en rubrikfil i en katalog som är lokal för projektet använde vi citattecken med -instruktionenimport:import "file";. Använd vinkelparenteser för att kompilera en rubrikenhet från ett systemhuvud i dina egna projekt:import <file>;Skapa lösningen genom att välja Skapa>bygglösning på huvudmenyn. Kör den för att se att den genererar förväntade utdata:
Pythagorean triple a:2 b:3 c:13
I dina egna projekt upprepar du den här processen för att kompilera huvudfilerna som du vill importera som rubrikenheter.
Om du bara vill konvertera några få huvudfiler till rubrikenheter är den här metoden bra. Men om du har många huvudfiler som du vill kompilera och den potentiella förlusten av byggprestanda uppvägs av bekvämligheten med att låta byggsystemet hantera dem automatiskt kan du läsa följande avsnitt.
Om du är intresserad av att specifikt importera STL-bibliotekshuvuden som rubrikenheter kan du läsa Genomgång: Importera STL-bibliotek som rubrikenheter.
Metod 2: Genomsök automatiskt efter och bygg header-enheter
Eftersom det tar tid att söka igenom alla dina källfiler efter rubrikenheter och tid för att skapa dem, passar följande metod bäst för mindre projekt. Det garanterar inte optimal bygggenomströmning.
Den här metoden kombinerar två Visual Studio-projektinställningar:
-
Genomsökningskällor för modulberoenden gör att byggsystemet anropar kompilatorn för att säkerställa att alla importerade moduler och rubrikenheter skapas innan de filer som är beroende av dem kompileras. När de kombineras med Översätt inkluderar till import, kompileras alla huvudfiler som ingår i din källa som också anges i en
header-units.jsonfil som finns i samma katalog som rubrikfilen till rubrikenheter. -
Translate Includes to Imports behandlar en rubrikfil som en
importom#includerefererar till en rubrikfil som kan kompileras som en rubrikenhet (som anges i enheader-units.jsonfil) och en kompilerad rubrikenhet är tillgänglig för huvudfilen. Annars behandlas rubrikfilen som en vanlig#include. Filenheader-units.jsonanvänds för att automatiskt skapa rubrikenheter för varje#include, utan symbolduplicering.
Du kan aktivera de här inställningarna i egenskaperna för projektet. Det gör du genom att högerklicka på projektet i Solution Explorer och välja Egenskaper. Välj sedan Konfigurationsegenskaper>C/C++>Allmänt.
Genomsökningskällor för modulberoenden kan anges för alla filer i projektet i Projektegenskaper som visas här, eller för enskilda filer i Filegenskaper. Moduler och rubrikenheter genomsöks alltid. Ange det här alternativet när du har en .cpp fil som importerar rubrikenheter som du vill skapa automatiskt och kanske inte har skapats ännu.
De här inställningarna fungerar tillsammans för att automatiskt skapa och importera rubrikenheter under följande villkor:
-
Sök källor för modulberoenden söker igenom dina källor efter filerna och deras beroenden som kan behandlas som huvudenheter. Filer som har tillägget
.ixx, och filer som har filegenskaperna>C/C++>Kompilera som-egenskap inställda på Kompilera som C++-rubrikenhet (/export), genomsöks alltid oavsett den här inställningen. Kompilatorn söker också efterimport-uttalanden för att identifiera beroenden av huvudenheter. Om/translateIncludeanges söker kompilatorn också efter#includedirektiv som också anges i enheader-units.jsonfil som ska behandlas som rubrikenheter. Ett beroendediagram skapas av alla moduler och huvudenheter i projektet. -
Översätt Includes till Imports När kompilatorn stöter på en
#include-instruktion och det finns en matchande huvudenhetsfil (.ifc) för den specificerade huvudfilen, importerar kompilatorn huvudenhetsfilen i stället för att behandla huvudfilen som en#include. I kombination med Sök efter beroenden hittar kompilatorn alla huvudfiler som kan kompileras till rubrikenheter. En tillåtlist konsulteras av kompilatorn för att avgöra vilka headerfiler som kan kompileras till headerenheter. Den här listan lagras i enheader-units.jsonfil som måste finnas i samma katalog som den inkluderade filen. Du kan se ett exempel på enheader-units.jsonfil under installationskatalogen för Visual Studio. Till exempel%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\header-units.jsonanvänds av kompilatorn för att avgöra om en standardmallbiblioteksrubrik kan kompileras till en rubrikenhet. Den här funktionen existerar för att utgöra en brygga med befintlig kod och dra nytta av vissa fördelar med header-enheter.
Filen header-units.json har två syften. Förutom att ange vilka huvudfiler som kan kompileras till rubrikenheter minimerar det duplicerade symboler för att öka byggdataflödet. Mer information om symbolduplicering finns i Referens för C++ header-units.json.
Dessa växlar och header-unit.json ger några av fördelarna med rubrikenheter. Bekvämligheten kommer till priset av bygggenomströmningen. Den här metoden kanske inte är den bästa för större projekt eftersom den inte garanterar optimala byggtider. Samma huvudfiler kan också bearbetas upprepade gånger, vilket ökar byggtiden. Bekvämligheten kan dock vara värd det beroende på projektet.
De här funktionerna är utformade för äldre kod. För ny kod går du till moduler i stället för rubrikenheter eller #include filer. En självstudiekurs om hur du använder moduler finns i Självstudie om namnmoduler (C++).
Ett exempel på hur den här tekniken används för att importera STL-huvudfiler som rubrikenheter finns i Genomgång: Importera STL-bibliotek som rubrikenheter.
Konsekvenser för förprocessorn
Förprocessorn som överensstämmer med standarden C99/C++11 krävs för att skapa och använda headerenheter. Kompilatorn aktiverar den nya C99/C++11-överensstämmande förprocessorn när huvudenheter kompileras genom att implicit lägga till /Zc:preprocessor på kommandoraden när någon form av /exportHeader används. Om du försöker inaktivera det resulterar det i ett kompileringsfel.
Aktivering av den nya förprocessorn påverkar processeringen av variadiska makron. Mer information finns i avsnittet anmärkningar om variadiska makron.
Se även
/translateInclude
/exportHeader
/headerUnit
header-units.json
Jämför rubrikenheter, moduler och förkompilerade rubriker
Översikt över moduler i C++
Självstudie: Importera C++-standardbiblioteket med hjälp av moduler
Genomgång: Importera STL-bibliotek som rubrikenheter