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
std
estd.compat
e 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 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 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.compat
esporta tutti gli elementi instd
e aggiunge gli spazi dei nomi globali del runtime C, inclusi::printf
,::fopen
,::size_t
,::strlen
e così via. Il modulostd.compat
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;
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_arg
e 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
std
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 modulo denominato
std
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 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.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 principali opzioni della riga di comando in questo esempio sono:
Interruttore 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 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é stiamo compilando il file del modulostd.ixx
. -
/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
) come file di origine del modulo (.ixx
) che si sta compilando. Nell'esempio, il fileifc
generato èstd.ifc
per impostazione predefinita perché stiamo compilando il file del modulostd.ixx
.
-
Importare la raccolta
std
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 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.obj
Non è necessario specificare
/reference "std=std.ifc"
nella riga di comando in questo esempio perché il compilatore cerca automaticamente il file.ifc
corrispondente al nome del modulo specificato dall'istruzioneimport
. Quando il compilatore rilevaimport std;
può trovarestd.ifc
se si trova nella stessa directory del codice sorgente. Se il file.ifc
si trova in una directory diversa dal codice sorgente, usare l'opzione del compilatore/reference
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 così. È 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 per compilare il modulo denominato
std
della libreria standard e il passaggio della compilazione dell'applicazione aggiungendoli alla riga di comando con"%VCToolsInstallDir%\modules\std.ixx"
. Inserirlo prima di qualsiasi file.cpp
che utilizza il modulostd
.Per impostazione predefinita, il nome dell'eseguibile di output viene ricavato dal primo file di input. Usare l'opzione del compilatore
/Fe
per specificare il nome del file eseguibile desiderato. Questa esercitazione illustra la compilazione del modulo denominatostd
come 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.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 modulo std.compat
fornisce tutte le funzionalità del modulo di std
, 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 esempio ::printf
, ::scanf
, ::fopen
, ::size_t
e 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\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
usando 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.ifc
per elaborareimport std.compat;
perchéstd.compat
si basa sustd
. Si tratta di un artefatto visibile solo durante la 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;
. Questo è un elemento disponibile solo in fase di compilazione. Non viene spedito 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 oggetto vengonostd.obj
estd.compat.obj
per impostazione predefinita perché vengono compilati i file del modulostd.ixx
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
) come file di origine del modulo (.ixx
) che si sta compilando. Nell'esempio i fileifc
generati vengonostd.ifc
estd.compat.ifc
per impostazione predefinita perché vengono compilati i file del modulostd.ixx
estd.compat.ixx
.
-
Importare la raccolta
std.compat
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 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#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 file.ifc
che corrisponde al nome del modulo in un'istruzioneimport
. Quando il compilatore rilevaimport std.compat;
trovastd.compat.ifc
poiché lo abbiamo inserito nella stessa directory del codice sorgente, sollevandoci dalla necessità di specificarlo nella riga di comando. Se il file.ifc
si trova in una directory diversa da quella del codice sorgente o ha un nome diverso, usare l'opzione del compilatore/reference
per farvi riferimento.Quando si importa
std.compat
, è necessario collegarsi sia astd.compat
che astd.obj
perchéstd.compat
usa il codice instd.obj
.Se si sta costruendo un singolo progetto, è possibile combinare i passaggi per compilare i moduli della libreria standard nominati
std
estd.compat
aggiungendo"%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.cpp
che li utilizza e specificare/Fe
per denominare ilexe
costruito, 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.obj
In questo esempio, la compilazione del codice sorgente e il collegamento dell'implementazione del modulo nell'applicazione sono passaggi separati. Non devono esserlo. È 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 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
, INFINITY
e INT_MIN
sono definite da <limits.h>
, che è possibile includere. Tuttavia, se si import std;
è possibile usare numeric_limits<double>::quiet_NaN()
e numeric_limits<double>::infinity()
anziché NAN
e INFINITY
e 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