Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Informazioni su come importare la libreria standard C++ usando i moduli della libreria C++. Ciò comporta una compilazione più rapida ed è più affidabile rispetto all'uso di file di intestazione o unità di intestazione o intestazioni precompilate (PCH).
In questa esercitazione vengono fornite informazioni su:
- Come importare la libreria standard come modulo dalla riga di comando.
- Vantaggi delle prestazioni e dell'usabilità dei moduli.
- I due moduli della libreria standard
stdestd.compate la differenza tra di essi.
Prerequisiti
Questa esercitazione richiede Visual Studio 2022 17.5 o versione successiva.
Introduzione ai moduli di libreria standard
La semantica dei file di intestazione può cambiare a seconda delle definizioni di macro, dell'ordine in cui li includi e rallentano la compilazione. I moduli risolvono questi problemi.
È ora possibile importare la libreria standard come modulo anziché come tangente di file di intestazione. Questo è molto più veloce e affidabile rispetto all'inclusione di file di intestazione, unità di intestazione o intestazioni precompilate (PCH).
La libreria standard C++23 introduce due moduli denominati: std e std.compat:
-
stdesporta le dichiarazioni e i nomi definiti nello spazio dei nomi della libreria standard C++std, ad esempiostd::vector. Esporta anche il contenuto delle intestazioni wrapper C, ad esempio<cstdio>e<cstdlib>, che forniscono funzioni comestd::printf(). Le funzioni C definite nello spazio dei nomi globale, ad esempio::printf(), non vengono esportate. Ciò migliora la situazione in cui l'inclusione di un'intestazione wrapper C come<cstdio>eo comporta anche l'inclusione di file di intestazione C comestdio.h, che introducono le versioni del namespace globale di C. Questo non è un problema se si importastd. -
std.compatesporta tutti gli elementi instde aggiunge gli spazi dei nomi globali del runtime C, inclusi::printf,::fopen,::size_t,::strlene così via. Il modulostd.compatsemplifica l'uso delle codebase che fanno riferimento a molte funzioni/tipi di runtime C nello spazio dei nomi globale.
Il compilatore importa l'intera libreria standard quando si usa import std; o import std.compat; ed esegue operazioni più veloci rispetto all'importazione di un singolo file di intestazione. È più veloce inserire l'intera libreria standard con import std; (o import std.compat) rispetto a #include <vector>, ad esempio.
Poiché i moduli denominati non espongono macro, macro come assert, errno, offsetof, va_arge altre non sono disponibili quando si importano std o std.compat. Per considerazioni sui moduli denominati della libreria standard, vedere per le soluzioni alternative.
Informazioni sui moduli C++
I file di intestazione sono il modo in cui le dichiarazioni e le definizioni sono state condivise tra i file di origine in C++. Prima dei moduli della libreria standard, è necessario includere la parte della libreria standard necessaria con una direttiva come #include <vector>. I file di intestazione sono fragili e difficili da comporre perché la semantica può cambiare a seconda dell'ordine in cui sono incluse o se determinate macro sono definite. Rallentano anche la compilazione perché vengono rielaborati da ogni file di origine che li include.
C++20 introduce un'alternativa moderna denominata moduli . In C++23 è stato possibile capitalizzare il supporto del modulo per introdurre moduli denominati per rappresentare la libreria standard.
Come i file di intestazione, i moduli consentono di condividere dichiarazioni e definizioni tra i file di origine. A differenza dei file di intestazione, tuttavia, i moduli non sono fragili e sono più facili da comporre perché la semantica non cambia a causa delle definizioni di macro o dell'ordine in cui vengono importate. Il compilatore può elaborare i moduli molto più velocemente di quanto possa elaborare #include file e usa meno memoria in fase di compilazione. I moduli denominati non espongono definizioni di macro o dettagli di implementazione privata.
Questo articolo illustra il nuovo e migliore modo per utilizzare la libreria standard. Per altre informazioni sui modi alternativi per utilizzare la libreria standard, vedere Confrontare unità di intestazione, moduli e intestazioni precompilate.
Importare la libreria standard con std
Negli esempi seguenti viene illustrato come utilizzare la libreria standard come modulo usando il compilatore della riga di comando. Per informazioni su come eseguire questa operazione nell'IDE di Visual Studio, vedere Build ISO C++23 Standard Library Modules.
L'istruzione import std; o import std.compat; importa la libreria standard nell'applicazione. Prima di tutto, è necessario compilare la libreria standard denominata modules in formato binario. I passaggi seguenti illustrano come.
Esempio: Come costruire e importare std
Aprire un prompt dei comandi degli strumenti nativi x86 per Visual Studio: dal menu Start di Windows, digitare nativo x86 e il prompt dovrebbe essere visualizzato nell'elenco delle app. Assicurarsi che il prompt sia per Visual Studio 2022 versione 17.5 o successiva. Se si usa la versione errata del prompt, vengono visualizzati errori. Gli esempi usati in questa esercitazione sono relativi alla shell CMD.
Creare una directory, ad esempio
%USERPROFILE%\source\repos\STLModules, e impostarla come directory corrente. Se si sceglie una directory a cui non si ha accesso in scrittura, si otterranno errori durante la compilazione.Compilare il modulo denominato
stdcon il comando seguente:cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx"Se si verificano errori, assicurarsi di usare la versione corretta del prompt dei comandi.
Compilare il modulo denominato
stdusando le stesse impostazioni del compilatore che si intende usare con il codice che importa il modulo compilato. Se si dispone di una soluzione multiprogetto, è possibile compilare la libreria standard denominata module una sola volta e quindi farvi riferimento da tutti i progetti usando l'opzione del compilatore/reference.Usando il comando del compilatore precedente, il compilatore restituisce due file:
-
std.ifcè la rappresentazione binaria compilata dell'interfaccia del modulo denominata consultata dal compilatore per elaborare l'istruzioneimport std;. Si tratta di un artefatto solo in fase di compilazione. Non viene fornito con la tua applicazione. -
std.objcontiene l'implementazione del modulo denominato. Aggiungerestd.objalla riga di comando quando si compila l'app di esempio per collegare in modo statico le funzionalità usate dalla libreria standard all'applicazione.
Le principali opzioni della riga di comando in questo esempio sono:
Interruttore Significato /std:c++latestUsare la versione più recente dello standard e della libreria del linguaggio C++. Anche se il supporto dei moduli è disponibile in /std:c++20, è necessaria la libreria standard più recente per ottenere il supporto per i moduli denominati della libreria standard./EHscUsare la gestione delle eccezioni C++, ad eccezione delle funzioni contrassegnate extern "C"./W4L'uso /W4è in genere consigliato, soprattutto per i nuovi progetti, perché abilita tutti gli avvisi di livello 1, livello 2, livello 3 e 4 (informativo), che consentono di rilevare i potenziali problemi in anticipo. Fornisce essenzialmente avvisi simili a lint che consentono di garantire il minor numero possibile di errori di codice difficili da trovare./cEseguire la compilazione senza collegamento, perché a questo punto si sta creando solo l'interfaccia binaria denominata module. È possibile controllare il nome del file dell'oggetto e il nome file dell'interfaccia del modulo denominato con le opzioni seguenti:
-
/Foimposta il nome del file oggetto. Ad esempio,/Fo:"somethingelse". Per impostazione predefinita, il compilatore usa lo stesso nome per il file oggetto del file di origine del modulo (.ixx) che si sta compilando. Nell'esempio, il nome del file dell'oggetto èstd.objper impostazione predefinita perché stiamo compilando il file del modulostd.ixx. -
/ifcOutputimposta il nome del file di interfaccia del modulo denominato (.ifc). Ad esempio,/ifcOutput "somethingelse.ifc". Per impostazione predefinita, il compilatore usa lo stesso nome per il file di interfaccia del modulo (.ifc) come file di origine del modulo (.ixx) che si sta compilando. Nell'esempio, il fileifcgenerato èstd.ifcper impostazione predefinita perché stiamo compilando il file del modulostd.ixx.
-
Importare la raccolta
stdcreata creando prima un file denominatoimportExample.cppcon il contenuto seguente:// requires /std:c++latest import std; int main() { std::cout << "Import the STL library for best performance\n"; std::vector<int> v{5, 5, 5}; for (const auto& e : v) { std::cout << e; } }Nel codice precedente
import std;sostituisce#include <vector>e#include <iostream>. L'istruzioneimport std;rende disponibile tutta la libreria standard con un'unica istruzione. L'importazione dell'intera libreria standard è spesso molto più veloce rispetto all'elaborazione di un singolo file di intestazione della libreria standard, ad esempio#include <vector>.Compilate l'esempio utilizzando il comando seguente nella stessa directory del passaggio precedente:
cl /c /std:c++latest /EHsc /nologo /W4 /reference "std=std.ifc" importExample.cpp link importExample.obj std.objNon è necessario specificare
/reference "std=std.ifc"nella riga di comando in questo esempio perché il compilatore cerca automaticamente il file.ifccorrispondente al nome del modulo specificato dall'istruzioneimport. Quando il compilatore rilevaimport std;può trovarestd.ifcse si trova nella stessa directory del codice sorgente. Se il file.ifcsi trova in una directory diversa dal codice sorgente, usare l'opzione del compilatore/referenceper farvi riferimento.In questo esempio, la compilazione del codice sorgente e il collegamento dell'implementazione del modulo nell'applicazione sono passaggi separati. Non devono essere così. È possibile usare
cl /std:c++latest /EHsc /nologo /W4 /reference "std=std.ifc" importExample.cpp std.objper compilare e collegare in un unico passaggio. Tuttavia, può essere utile compilare e collegare separatamente perché è sufficiente compilare la libreria standard denominata module una sola volta, quindi è possibile farvi riferimento dal progetto o da più progetti, nel passaggio di collegamento della compilazione.Se si compila un singolo progetto, è possibile combinare i passaggi per compilare il modulo denominato
stddella libreria standard e il passaggio della compilazione dell'applicazione aggiungendoli alla riga di comando con"%VCToolsInstallDir%\modules\std.ixx". Inserirlo prima di qualsiasi file.cppche utilizza il modulostd.Per impostazione predefinita, il nome dell'eseguibile di output viene ricavato dal primo file di input. Usare l'opzione del compilatore
/Feper specificare il nome del file eseguibile desiderato. Questa esercitazione illustra la compilazione del modulo denominatostdcome passaggio separato perché è sufficiente compilare la libreria standard denominata module una sola volta e quindi farvi riferimento dal progetto o da più progetti. Può essere conveniente costruire tutto insieme, come mostrato dalla riga di comando seguente:cl /FeimportExample /std:c++latest /EHsc /nologo /W4 "%VCToolsInstallDir%\modules\std.ixx" importExample.cppData la riga di comando precedente, il compilatore genera un eseguibile denominato
importExample.exe. Quando viene eseguito, genera l'output seguente:Import the STL library for best performance 555
Importare la libreria standard e le funzioni C globali con std.compat
La libreria standard C++ include la libreria standard ISO C. Il modulo std.compat fornisce tutte le funzionalità del modulo di std, ad esempio std::vector, std::cout, std::printf, std::scanfe così via. Ma fornisce anche le versioni dello spazio dei nomi globali di queste funzioni, ad esempio ::printf, ::scanf, ::fopen, ::size_te così via.
Il modulo denominato std.compat è un livello di compatibilità fornito per semplificare la migrazione del codice esistente che fa riferimento alle funzioni di runtime C nello spazio dei nomi globale. Per evitare di aggiungere nomi allo spazio dei nomi globale, usare import std;. Se è necessario semplificare la migrazione di una codebase che usa molte funzioni di runtime C non qualificate (spazio dei nomi globale), usare import std.compat;. Per evitare di dover qualificare tutti i nomi globali con std::, questo fornisce i nomi di runtime C dello spazio dei nomi globali. Se non si dispone di codice esistente che usa le funzioni di runtime C dello spazio dei nomi globale, non è necessario usare import std.compat;. Se nel codice si chiamano solo alcune funzioni di runtime C, potrebbe essere preferibile usare import std; e qualificare i pochi nomi di runtime C necessari nello spazio dei nomi globale con std::. Ad esempio, std::printf(). Se viene visualizzato un errore simile a error C3861: 'printf': identifier not found quando si tenta di compilare il codice, provare a usare import std.compat; per importare le funzioni di runtime C dello spazio dei nomi globale.
Esempio: Come costruire e importare std.compat
Prima di poter usare import std.compat; è necessario compilare il file di interfaccia del modulo presente nel modulo del codice sorgente in std.compat.ixx. Visual Studio fornisce il codice sorgente per il modulo in modo che sia possibile compilare il modulo usando le impostazioni del compilatore corrispondenti al progetto. I passaggi sono simili a per la compilazione del modulo denominato std. Il modulo denominato std viene creato per primo perché std.compat dipende da esso:
Aprire un prompt dei comandi degli strumenti nativi per Visual Studio: dal menu Start di Windows, digitare x86 nativo e il prompt verrà visualizzato nell'elenco delle app. Assicurarsi che il prompt sia per Visual Studio 2022 versione 17.5 o successiva. Se si usa la versione errata del prompt, si otterranno errori del compilatore.
Creare una directory per provare questo esempio, ad esempio
%USERPROFILE%\source\repos\STLModulese impostarla come directory corrente. Se si sceglie una directory a cui non si ha accesso in scrittura, verranno visualizzati errori.Compilare i moduli denominati
stdestd.compatcon il comando seguente:cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx" "%VCToolsInstallDir%\modules\std.compat.ixx"È necessario compilare
stdestd.compatusando le stesse impostazioni del compilatore che si intende usare con il codice che li importerà. Se si dispone di una soluzione multiprogetto, è possibile compilarli una sola volta e quindi farvi riferimento da tutti i progetti usando l'opzione del compilatore/reference.Se si verificano errori, assicurarsi di usare la versione corretta del prompt dei comandi.
Il compilatore restituisce quattro file dai due passaggi precedenti:
-
std.ifcè l'interfaccia binaria denominata module compilata consultata dal compilatore per elaborare l'istruzioneimport std;. Il compilatore consulta anchestd.ifcper elaborareimport std.compat;perchéstd.compatsi basa sustd. Si tratta di un artefatto solo in fase di compilazione. Non viene fornito con la tua applicazione. -
std.objcontiene l'implementazione della libreria standard. -
std.compat.ifcè l'interfaccia binaria denominata module compilata consultata dal compilatore per elaborare l'istruzioneimport std.compat;. Si tratta di un artefatto solo in fase di compilazione. Non viene fornito con la tua applicazione. -
std.compat.objcontiene l'implementazione. Tuttavia, la maggior parte dell'implementazione viene fornita dastd.obj. Aggiungerestd.objalla riga di comando quando si compila l'app di esempio per collegare in modo statico le funzionalità usate dalla libreria standard all'applicazione.
È possibile controllare il nome del file dell'oggetto e il nome file dell'interfaccia del modulo denominato con le opzioni seguenti:
-
/Foimposta il nome del file oggetto. Ad esempio,/Fo:"somethingelse". Per impostazione predefinita, il compilatore usa lo stesso nome per il file oggetto del file di origine del modulo (.ixx) che si sta compilando. Nell'esempio i nomi dei file oggetto vengonostd.objestd.compat.objper impostazione predefinita perché vengono compilati i file del modulostd.ixxestd.compat.ixx. -
/ifcOutputimposta il nome del file di interfaccia del modulo denominato (.ifc). Ad esempio,/ifcOutput "somethingelse.ifc". Per impostazione predefinita, il compilatore usa lo stesso nome per il file di interfaccia del modulo (.ifc) come file di origine del modulo (.ixx) che si sta compilando. Nell'esempio i fileifcgenerati vengonostd.ifcestd.compat.ifcper impostazione predefinita perché vengono compilati i file del modulostd.ixxestd.compat.ixx.
-
Importare la raccolta
std.compatcreando prima di tutto un file denominatostdCompatExample.cppcon il contenuto seguente:import std.compat; int main() { printf("Import std.compat to get global names like printf()\n"); std::vector<int> v{5, 5, 5}; for (const auto& e : v) { printf("%i", e); } }Nel codice precedente
import std.compat;sostituisce#include <cstdio>e#include <vector>. L'istruzioneimport std.compat;rende disponibili le funzioni di runtime standard e C con un'unica istruzione. L'importazione di questo modulo denominato, che include la libreria standard C++ e le funzioni dello spazio dei nomi globale della libreria di runtime C, è più veloce rispetto all'elaborazione di un singolo#includecome#include <vector>.Compilare l'esempio usando il comando seguente:
cl /std:c++latest /EHsc /nologo /W4 stdCompatExample.cpp link stdCompatExample.obj std.obj std.compat.objNon è stato necessario specificare
std.compat.ifcnella riga di comando perché il compilatore cerca automaticamente il file.ifcche corrisponde al nome del modulo in un'istruzioneimport. Quando il compilatore rilevaimport std.compat;trovastd.compat.ifcpoiché lo abbiamo inserito nella stessa directory del codice sorgente, sollevandoci dalla necessità di specificarlo nella riga di comando. Se il file.ifcsi trova in una directory diversa da quella del codice sorgente o ha un nome diverso, usare l'opzione del compilatore/referenceper farvi riferimento.Quando si importa
std.compat, è necessario collegarsi sia astd.compatche astd.objperchéstd.compatusa il codice instd.obj.Se si sta costruendo un singolo progetto, è possibile combinare i passaggi per compilare i moduli della libreria standard nominati
stdestd.compataggiungendo"%VCToolsInstallDir%\modules\std.ixx"e"%VCToolsInstallDir%\modules\std.compat.ixx"nell'ordine indicato alla riga di comando. Questa esercitazione illustra la compilazione dei moduli della libreria standard come passaggio separato perché è sufficiente compilare la libreria standard denominata modules una sola volta e quindi farvi riferimento dal progetto o da più progetti. Tuttavia, se è utile costruirli tutti contemporaneamente, assicurarsi di inserirli prima di qualsiasi file.cppche li utilizza e specificare/Feper denominare ilexecostruito, come illustrato in questo esempio di seguito.cl /c /FestdCompatExample /std:c++latest /EHsc /nologo /W4 "%VCToolsInstallDir%\modules\std.ixx" "%VCToolsInstallDir%\modules\std.compat.ixx" stdCompatExample.cpp link stdCompatExample.obj std.obj std.compat.objIn questo esempio, la compilazione del codice sorgente e il collegamento dell'implementazione del modulo nell'applicazione sono passaggi separati. Non devono essere così. È possibile usare
cl /std:c++latest /EHsc /nologo /W4 stdCompatExample.cpp std.obj std.compat.objper compilare e collegare in un unico passaggio. Tuttavia, può essere utile compilare e collegare separatamente perché è sufficiente compilare la libreria standard denominata modules una sola volta, quindi è possibile farvi riferimento dal progetto o da più progetti nel passaggio di collegamento della compilazione.Il comando del compilatore precedente genera un eseguibile denominato
stdCompatExample.exe. Quando viene eseguito, genera l'output seguente:Import std.compat to get global names like printf() 555
Considerazioni sui moduli nominati della libreria standard
Il versionamento per i moduli denominati è lo stesso che per le intestazioni. I file di modulo denominati .ixx vengono installati insieme alle intestazioni, ad esempio: "%VCToolsInstallDir%\modules\std.ixx", che corrisponde a C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.38.33130\modules\std.ixx nella versione degli strumenti usati al momento della scrittura. Selezionare la versione del modulo denominato nello stesso modo in cui si sceglie la versione del file di intestazione da usare, ovvero dalla directory da cui si fa riferimento.
Non mescolare le unità di header e i moduli denominati. Ad esempio, non import <vector>; e import std; nello stesso file.
Non mescolare l'importazione di file di intestazione della libreria standard C++ con i moduli denominati std o std.compat. Ad esempio, non #include <vector> e import std; nello stesso file. Tuttavia, è possibile includere intestazioni C e importare moduli denominati nello stesso file. Ad esempio, è possibile import std; e #include <math.h> nello stesso file. Non includere la versione della libreria standard C++ <cmath>.
Non è necessario difendersi più volte dall'importazione di un modulo. Ciò significa che non sono necessarie le guardie per l'intestazione in stile #ifndef nei moduli. Il compilatore sa quando è già stato importato un modulo denominato e ignora i tentativi duplicati a tale scopo.
Se è necessario usare la macro assert(), #include <assert.h>.
Se è necessario utilizzare la macro errno, #include <errno.h>. Poiché i moduli denominati non espongono macro, questa è la soluzione alternativa se è necessario verificare la presenza di errori da <math.h>, ad esempio.
Le macro come NAN, INFINITYe INT_MIN sono definite da <limits.h>, che è possibile includere. Tuttavia, se si import std; è possibile usare std::numeric_limits<double>::quiet_NaN() e std::numeric_limits<double>::infinity() anziché NAN e INFINITYe std::numeric_limits<int>::min() anziché INT_MIN.
Sommario
In questa esercitazione è stata importata la libreria standard usando i moduli. Successivamente, scopri come creare e importare moduli personalizzati nel tutorial sui moduli nominati di in C++.
Vedere anche
Confrontare unità di intestazione, moduli e intestazioni precompilate
Panoramica dei moduli in C++
Presentazione dei moduli C++ in Visual Studio
Spostamento di un progetto in C++ denominato Modules