Esercitazione: Importare la libreria standard C++ usando moduli dalla riga di comando
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
std
della libreria standard estd.compat
la differenza tra di essi.
Prerequisiti
Questa esercitazione richiede Visual Studio 2022 17.5 o versione successiva.
Introduzione ai moduli di libreria standard
I file di intestazione soffrono di semantica che possono cambiare a seconda delle definizioni di macro, dell'ordine in cui sono inclusi 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 più affidabile rispetto all'inclusione di file di intestazione o unità di intestazione o intestazioni precompilate (PCH).
La libreria standard C++23 introduce due moduli denominati: std
e std.compat
:
std
esporta le dichiarazioni e i nomi definiti nello spazio dei nomistd
della libreria standard C++, ad esempiostd::vector
. Esporta anche il contenuto delle intestazioni wrapper C,<cstdio>
ad esempio 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>
include anche i file di intestazione C comestdio.h
, che portano le versioni dello spazio dei nomi globale C. Questo non è un problema se si importastd
.std.compat
esporta tutti gli elementi instd
e aggiunge gli spazi dei nomi globali del runtime C, ad::printf
esempio ,::fopen
::size_t
,::strlen
, e così via. Ilstd.compat
modulo semplifica 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;
e lo esegue più velocemente 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_arg
, e altre non sono disponibili quando si importa std
o std.compat
. Per le soluzioni alternative, vedere Considerazioni sulla libreria Standard denominata module.
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 i #include
file e usa meno memoria in fase di compilazione. I moduli denominati non espongono definizioni di macro o dettagli di implementazione privata.
Per informazioni approfondite sui moduli, vedere Panoramica dei moduli in C++ Che illustra anche l'uso della libreria standard C++ come moduli, ma usa un modo precedente e sperimentale per farlo.
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 le unità di intestazione, i moduli e le 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 Compilare moduli della libreria standard ISO C++23.
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 compilare e importare std
Aprire un prompt dei comandi di Strumenti nativi x86 per Visual Studio: dal menu Start di Windows digitare x86 nativo 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, si otterranno 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
std
modulo denominato con 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
std
modulo denominato usando 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/reference
compilatore.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 l'applicazione.std.obj
contiene l'implementazione del modulo denominato. Aggiungerestd.obj
alla riga di comando quando si compila l'app di esempio per collegare in modo statico le funzionalità usate dalla libreria standard all'applicazione.
Le opzioni della riga di comando della chiave in questo esempio sono:
Commutatore Significato /std:c++:latest
Usare 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./EHsc
Usare la gestione delle eccezioni C++, ad eccezione delle funzioni contrassegnate da extern "C"
./W4
L'uso di /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. /c
Eseguire 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:
/Fo
imposta 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.obj
per impostazione predefinita perché viene compilato il filestd.ixx
del modulo ./ifcOutput
imposta 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
) del file di origine del modulo (.ixx
) che si sta compilando. Nell'esempio il file generatoifc
èstd.ifc
per impostazione predefinita perché viene compilato il filestd.ixx
del modulo .
Importare la
std
libreria creata creando prima un file denominatoimportExample.cpp
con 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
import std;
precedente 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,#include <vector>
ad esempio .Compilare l'esempio usando 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.obj
Non è necessario specificare
/reference "std=std.ifc"
nella riga di comando di questo esempio perché il compilatore cerca automaticamente il.ifc
file corrispondente al nome del modulo specificato dall'istruzioneimport
. Quando viene rilevato dal compilatoreimport std;
, può trovarestd.ifc
se si trova nella stessa directory del codice sorgente. Se il.ifc
file si trova in una directory diversa dal codice sorgente, usare l'opzione del/reference
compilatore per 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. È possibile usare
cl /std:c++latest /EHsc /nologo /W4 /reference "std=std.ifc" importExample.cpp std.obj
per 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 della compilazione della
std
libreria standard denominata module e il passaggio della compilazione dell'applicazione aggiungendo"%VCToolsInstallDir%\modules\std.ixx"
alla riga di comando. Inserirlo prima di tutti i.cpp
file che utilizzano ilstd
modulo.Per impostazione predefinita, il nome dell'eseguibile di output viene ricavato dal primo file di input. Usare l'opzione del
/Fe
compilatore per specificare il nome del file eseguibile desiderato. Questa esercitazione illustra la compilazione delstd
modulo denominato come passaggio separato perché è sufficiente compilare la libreria standard denominata module una sola volta e quindi farvi riferimento dal progetto o da più progetti. Ma può essere utile compilare tutto insieme, come illustrato dalla riga di comando seguente:cl /FeimportExample /std:c++latest /EHsc /nologo /W4 "%VCToolsInstallDir%\modules\std.ixx" importExample.cpp
Data 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 std.compat
modulo fornisce tutte le funzionalità del std
modulo, ad esempio std::vector
, std::cout
, std::printf
std::scanf
, e così via. Ma fornisce anche le versioni dello spazio dei nomi globali di queste funzioni, ad ::printf
esempio , ::scanf
::fopen
, ::size_t
, e così via.
Il std.compat
modulo denominato è 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;
. In questo modo vengono forniti i nomi di runtime C dello spazio dei nomi globali in modo che non sia necessario qualificare tutti i nomi globali con std::
. 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 dello spazio dei nomi globali necessari con std::
. Ad esempio: std::printf()
. Se viene visualizzato un errore simile error C3861: 'printf': identifier not found
a 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 compilare e importare std.compat
Prima di poter usare import std.compat;
è necessario compilare il file di interfaccia del modulo disponibile 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 std
modulo denominato. Il std
modulo denominato 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 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, si otterranno errori del compilatore.
Creare una directory per provare questo esempio, ad esempio
%USERPROFILE%\source\repos\STLModules
, e impostarla come directory corrente. Se si sceglie una directory a cui non si ha accesso in scrittura, verranno visualizzati errori.Compilare i moduli denominati
std
estd.compat
con il comando seguente:cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx" "%VCToolsInstallDir%\modules\std.compat.ixx"
È necessario compilare
std
estd.compat
usare 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/reference
compilatore.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 consultastd.ifc
anche per elaborareimport std.compat;
perchéstd.compat
si basa sustd
. Si tratta di un artefatto solo in fase di compilazione. Non viene fornito con l'applicazione.std.obj
contiene 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 l'applicazione.std.compat.obj
contiene l'implementazione. Tuttavia, la maggior parte dell'implementazione viene fornita dastd.obj
. Aggiungerestd.obj
alla 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:
/Fo
imposta 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 di oggetto sonostd.obj
estd.compat.obj
, per impostazione predefinita, perché vengono compilati i filestd.ixx
di modulo estd.compat.obj
./ifcOutput
imposta 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
) del file di origine del modulo (.ixx
) che si sta compilando. Nell'esempio i file generatiifc
sonostd.ifc
estd.compat.ifc
, per impostazione predefinita, perché vengono compilati i filestd.ixx
del modulo estd.compat.ixx
.
Importare la
std.compat
libreria creando prima di tutto un file denominatostdCompatExample.cpp
con 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
import std.compat;
precedente sostituisce#include <cstdio>
e#include <vector>
. L'istruzioneimport std.compat;
rende disponibili le funzioni della libreria standard e del runtime 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#include
come#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.obj
Non è stato necessario specificare
std.compat.ifc
nella riga di comando perché il compilatore cerca automaticamente il.ifc
file che corrisponde al nome del modulo in un'istruzioneimport
. Quando il compilatoreimport std.compat;
rileva che viene trovatostd.compat.ifc
perché lo si inserisce nella stessa directory del codice sorgente, che si basa sulla necessità di specificarlo nella riga di comando. Se il.ifc
file si trova in una directory diversa rispetto al codice sorgente o ha un nome diverso, usare l'opzione del/reference
compilatore per farvi riferimento.Quando si importa
std.compat
, è necessario collegarsi a estd.obj
std.compat
perchéstd.compat
usa il codice instd.obj
.Se si compila un singolo progetto, è possibile combinare i passaggi della compilazione della
std
libreria standard estd.compat
dei moduli denominati aggiungendo"%VCToolsInstallDir%\modules\std.ixx"
e"%VCToolsInstallDir%\modules\std.compat.ixx"
(in questo ordine) 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 compilarli tutti contemporaneamente, assicurarsi di inserirli prima di tutti i.cpp
file che li usano e specificare di denominare/Fe
il compilatoexe
come illustrato in questo esempio: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.obj
In questo esempio, la compilazione del codice sorgente e il collegamento dell'implementazione del modulo nell'applicazione sono passaggi separati. Non devono essere. È possibile usare
cl /std:c++latest /EHsc /nologo /W4 stdCompatExample.cpp std.obj std.compat.obj
per 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 denominati della libreria standard
Il controllo delle versioni per i moduli denominati è uguale a quello delle intestazioni. I .ixx
file di modulo denominati vengono installati insieme alle intestazioni, ad esempio , "%VCToolsInstallDir%\modules\std.ixx
che si risolve 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 stesura di questo articolo. 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 combinare e associare le unità di intestazione e i moduli denominati. Ad esempio, non import <vector>;
e import std;
nello stesso file.
Non combinare e associare l'importazione di file di intestazione della libreria standard C++ e 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 solo la versione <cmath>
della libreria standard C++.
Non è necessario difendersi più volte dall'importazione di un modulo. Ciò significa che non sono necessarie #ifndef
protezioni di intestazione di stile nei moduli. Il compilatore sa quando è già stato importato un modulo denominato e ignora i tentativi duplicati a tale scopo.
Se è necessario usare la assert()
macro, #include <assert.h>
.
Se è necessario utilizzare la errno
macro , #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, NAN
ad esempio , INFINITY
e INT_MIN
sono definite da <limits.h>
, che è possibile includere. Tuttavia, se è import std;
possibile usare numeric_limits<double>::quiet_NaN()
e numeric_limits<double>::infinity()
anziché NAN
e INFINITY
, anziché std::numeric_limits<int>::min()
INT_MIN
.
Riepilogo
In questa esercitazione è stata importata la libreria standard usando i moduli. Informazioni sulla creazione e l'importazione di moduli personalizzati nell'esercitazione sui moduli denominati in C++.
Vedi anche
Confrontare unità di intestazione, moduli e intestazioni precompilate
Panoramica dei moduli in C++
Panoramica dei moduli C++ in Visual Studio
Spostamento di un progetto in C++ denominato Modules
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per