Miglioramenti della conformità C++, modifiche del comportamento e correzioni di bug in Visual Studio 2022
Microsoft C/C++ in Visual Studio (MSVC) apporta miglioramenti alla conformità e correzioni di bug in ogni versione. Questo articolo elenca i miglioramenti significativi apportati dalla versione principale, quindi in base alla versione. Per passare direttamente alle modifiche per una versione specifica, usare i collegamenti In questo articolo .
Questo documento elenca le modifiche in Visual Studio 2022.
Per le modifiche apportate a Visual Studio 2019, vedere Miglioramenti della conformità di C++ in Visual Studio 2019.
Per le modifiche apportate a Visual Studio 2017, vedere Miglioramenti della conformità di C++ in Visual Studio 2017.
Per le modifiche apportate alle versioni precedenti, vedere Novità di Visual C++ da 2003 a 2015.
Miglioramenti della conformità in Visual Studio 2022 versione 17.11
Visual Studio 2022 versione 17.11 include i miglioramenti di conformità, le correzioni di bug e le modifiche del comportamento seguenti nel compilatore Microsoft C/C++.
Per un riepilogo approfondito delle modifiche apportate alla libreria dei modelli standard, incluse le modifiche di conformità, le correzioni di bug e i miglioramenti delle prestazioni, vedere STL Changelog VS 2022 17.11.
Stampare righe vuote con println
Per P3142R0, è ora facile generare una riga vuota con println
. Questa funzionalità è disponibile durante la compilazione con /std:c++latest
.
Prima di questa modifica, è stato scritto: println("");
Ora si scrive: println();
.
println();
equivale aprintln(stdout);
println(FILE* stream);
equivale aprintln(stream, "\n");
Attuato range_formatter
Per P2286R8, range_formatter
viene ora implementato. Questa funzionalità è disponibile durante la compilazione con /std:c++latest
.
Miglioramenti della conformità in Visual Studio 2022 versione 17.10
Visual Studio 2022 versione 17.10 include i miglioramenti di conformità, le correzioni di bug e le modifiche del comportamento seguenti nel compilatore Microsoft C/C++.
Per un riepilogo approfondito delle modifiche apportate alla libreria dei modelli standard, incluse le modifiche di conformità, le correzioni di bug e i miglioramenti delle prestazioni, vedere STL Changelog VS 2022 17.10.
Specializzazione dell'operatore di conversione con tipo restituito specificato in modo esplicito
Il compilatore usato per specializzare gli operatori di conversione in modo non corretto in alcuni casi, che potrebbe causare una mancata corrispondenza del tipo restituito. Queste specializzazioni non valide non vengono più eseguite. Si tratta di una modifica che causa un'interruzione del codice sorgente.
// Example 1
struct S
{
template<typename T> operator const T*();
};
void test()
{
S{}.operator int*(); // this is invalid now
S{}.operator const int*(); // this is valid
}
// Example 2
// In some cases, the overload resolution result may change
struct S
{
template <typename T> operator T*(); // overload 1
template <typename T> operator const T*(); // overload 2
};
void test()
{
S{}.operator int*(); // this used to call overload 2, now it calls overload 1
}
Aggiunta del supporto per #elifdef
e #elifndef
È stato aggiunto il supporto per WG21 P2334R1 (C++23) e WG14 N2645 (C++23) che ha introdotto le #elifdef
direttive del preprocessore e #elifndef
.
Richiede /std:clatest
o /std:c++latest
.
Prima:
#ifdef __cplusplus
#include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Dopo:
#ifdef __cplusplus
#include <atomic>
#elifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Applicazione di _Alignas
in un tipo strutturato in C
Si applica al linguaggio C (C17 e versioni successive). Aggiunta anche a Microsoft Visual Studio 17.9
Nelle versioni di Visual C++ precedenti a Visual Studio 2022 versione 17.9, se l'identificatore _Alignas
appare accanto a un tipo strutturato in una dichiarazione, non è stato applicato correttamente in base allo standard ISO-C.
// compile with /std:c17
#include <stddef.h>
struct Outer
{
_Alignas(32) struct Inner { int i; } member1;
struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");
Secondo lo standard ISO-C, questo codice deve essere compilato senza static_assert
generare una diagnostica.
La _Alignas
direttiva si applica solo alla variabile member1
membro . Non deve modificare l'allineamento di struct Inner
. Tuttavia, prima di Visual Studio 17.9.1, la diagnostica "allineamento non corretto" è stata generata. Il compilatore è allineato member2
a un offset di 32 byte all'interno del struct Outer
tipo.
Si tratta di una modifica che causa un'interruzione binaria, quindi viene ora generato un avviso quando questa modifica diventa effettiva. L'avviso C5274 viene ora generato al livello di avviso 1 per l'esempio precedente: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects)
.
Inoltre, nelle versioni precedenti di Visual Studio, quando l'identificatore _Alignas
è apparso accanto a una dichiarazione di tipo anonimo, è stato ignorato.
// compile with /std:c17
#include <stddef.h>
struct S
{
_Alignas(32) struct { int anon_member; };
int k;
};
static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");
In precedenza, entrambe static_assert
le istruzioni non sono riuscite durante la compilazione di questo codice. Il codice viene compilato, ma genera gli avvisi di livello 1 seguenti:
warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)
Per ottenere il comportamento precedente, sostituire _Alignas(N)
con __declspec(align(N))
. A differenza di _Alignas
, declspec(align)
si applica al tipo .
Avviso migliorato C4706
Si tratta di una modifica che causa un'interruzione del codice sorgente. In precedenza, il compilatore non rilevava la convenzione di wrapping di un'assegnazione tra parentesi, se l'assegnazione era destinata, per eliminare l'avviso C4706 sull'assegnazione all'interno di un'espressione condizionale. Il compilatore rileva ora le parentesi e elimina l'avviso.
#pragma warning(error: 4706)
struct S
{
auto mf()
{
if (value = 9)
return value + 4;
else
return value;
}
int value = 9;
};
Il compilatore genera ora anche l'avviso nei casi in cui la funzione non fa riferimento. In precedenza, poiché mf
è una funzione inline a cui non si fa riferimento, l'avviso C4706 non è stato generato per questo codice. Ora viene generato l'avviso:
error C4706: assignment used as a condition
note: if an assignment is intended you can enclose it in parentheses, '(e1 = e2)', to silence this warning
Per correggere questo avviso, usare un operatore di uguaglianza, value == 9
, se si tratta di ciò che è stato previsto. In alternativa, eseguire il wrapping dell'assegnazione tra parentesi, (value = 9)
, se l'assegnazione è prevista. In caso contrario, poiché la funzione non è referenziata, rimuoverla.
Miglioramenti della conformità in Visual Studio 2022 versione 17.9
Visual Studio 2022 versione 17.9 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche di comportamento seguenti nel compilatore Microsoft C/C++.
Per un riepilogo più ampio delle modifiche apportate alla libreria dei modelli standard, vedere STL Changelog VS 2022 17.9.
Applicazione di _Alignas
in un tipo strutturato in C
Nelle versioni di Visual C++ precedenti a Visual Studio 2022 versione 17.9, quando _Alignas
appare accanto a un tipo di struttura in una dichiarazione, non è stato applicato correttamente in base allo standard ISO-C. Ad esempio:
// compile with /std:c17
#include <stddef.h>
struct Outer
{
_Alignas(32) struct Inner { int i; } member1;
struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");
In base allo standard ISO-C, questo codice deve essere compilato senza generare static_assert
una diagnostica. La _Alignas
direttiva si applica solo alla variabile member1
membro . Non deve modificare l'allineamento di struct Inner
. Tuttavia, prima della versione 17.9.1 di Visual Studio, la diagnostica "allineamento non corretto" è stata generata. Il compilatore è allineato member2
a un offset di 32 byte all'interno di struct Outer
.
Correzione di questa modifica binaria che causa un'interruzione binaria, pertanto quando viene applicata questa modifica al comportamento viene generato un avviso. Per il codice precedente, l'avviso C5274, "_Alignas
non si applica più al tipo "Inner" (si applica solo agli oggetti dati dichiarati)" viene ora generato al livello di avviso 1.
Nelle versioni precedenti di Visual Studio, _Alignas
è stato ignorato quando appare accanto a una dichiarazione di tipo anonimo. Ad esempio:
// compile with /std:c17
#include <stddef.h>
struct S {
_Alignas(32) struct { int anon_member; };
int k;
};
static_assert(offsetof(struct S, k)==4, "incorrect offsetof");
static_assert(sizeof(struct S)==32, "incorrect size");
In precedenza, entrambe static_assert
le istruzioni non sono riuscite durante la compilazione di questo codice. Il codice ora viene compilato, ma con gli avvisi di livello 1 seguenti:
warning C5274: behavior change: _Alignas no longer applies to the type '<unnamed-tag>' (only applies to declared data objects)
warning C5273: behavior change: _Alignas on anonymous type no longer ignored (promoted members will align)
Se si vuole il comportamento precedente, sostituire _Alignas(N)
con __declspec(align(N))
. A differenza di _Alignas
, declspec(align)
può essere applicato a un tipo.
__VA_OPT__
è abilitato come estensione in /Zc:preprocessor
__VA_OPT__
è stato aggiunto a C++20 e C23. Prima dell'aggiunta, non c'era un modo standard per elidere una virgola in una macro variadic. Per garantire una migliore compatibilità con le versioni precedenti, __VA_OPT__
è abilitata nel preprocessore /Zc:preprocessor
basato su token in tutte le versioni del linguaggio.
Ad esempio, questa operazione viene compilata senza errori:
#define LOG_WRAPPER(message, ...) WRITE_LOG(__LINE__, message __VA_OPT__(, __VA_ARGS__))
// Failed to build under /std:c11, now succeeds.
LOG_WRAPPER("Log message");
LOG_WRAPPER("Log message with %s", "argument")
Linguaggio C23
Per C23, quando si usa l'opzione del /std:clatest
compilatore sono disponibili le opzioni seguenti:
Di seguito sono disponibili tutte le versioni del linguaggio C:
libreria standard C++
Funzionalità di C++23
formattable
,range_format
,format_kind
eset_debug_format()
come parte di intervalli di formattazione P2286R8<mdspan>
per P0009R18 e le successive modifiche di formulazione applicate allo standard C++23.format()
puntatori per P2510R3.
Miglioramenti della conformità in Visual Studio 2022 versione 17.8
Visual Studio 2022 versione 17.8 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche di comportamento seguenti nel compilatore Microsoft C/C++.
/FU
genera un errore
Il compilatore C usato per accettare l'opzione /FU
, anche se non supporta la compilazione gestita per qualche tempo. Ora genera un errore. I progetti che passano questa opzione devono limitarlo solo ai progetti C++/CLI.
libreria standard C++
I moduli denominati std
C++23 e std.compat
sono ora disponibili durante la compilazione con /std:c++20
.
Per un riepilogo più ampio delle modifiche apportate alla libreria standard C++, vedere STL Changelog VS 2022 17.8.
Miglioramenti della conformità in Visual Studio 2022 versione 17.7
Visual Studio 2022 versione 17.7 contiene i seguenti miglioramenti di conformità evidenziati, correzioni di bug e modifiche del comportamento nel compilatore Microsoft C/C++.
Aggiunta /std:clatest
al compilatore C
Questa opzione si comporta come l'opzione /std:c++latest
per il compilatore C++. L'opzione abilita tutte le funzionalità del compilatore e della libreria standard attualmente implementate proposte per lo standard C successivo, nonché alcune funzionalità in corso e sperimentali.
libreria standard C++
La <print>
libreria è ora supportata. Vedere P2093R14 output formattato.
Implementazione di views::cartesian_product
.
Per un riepilogo più ampio delle modifiche apportate alla libreria dei modelli standard, vedere STL Changelog VS 2022 17.7.
using
Conformità
In precedenza, la using
direttiva poteva causare la visibilità dei nomi degli spazi dei nomi usati quando non dovrebbero. Ciò potrebbe causare la ricerca di un nome non qualificato in uno spazio dei nomi anche quando non è attiva alcuna using
direttiva.
Ecco alcuni esempi del comportamento nuovo e precedente.
I riferimenti nei commenti seguenti a "(1)" indicano la chiamata a f<K>(t)
nello spazio dei nomi A
:
namespace A
{
template<typename K, typename T>
auto f2(T t)
{
return f<K>(t); // (1) Unqualified lookup should not find anything
}
}
namespace B
{
template<typename K, typename T>
auto f(T t) noexcept
{ // Previous behavior: This function was erroneously found during unqualified lookup at (1)
return A::f2<K>(t);
}
}
namespace C
{
template<typename T>
struct S {};
template<typename, typename U>
U&& f(U&&) noexcept; // New behavior: ADL at (1) correctly finds this function
}
namespace D
{
using namespace B;
void h()
{
D::f<void>(C::S<int>());
}
}
Lo stesso problema sottostante può causare il rifiuto del codice compilato in precedenza:
#include <memory>
namespace Addin {}
namespace Gui
{
using namespace Addin;
}
namespace Addin
{
using namespace std;
}
// This previously compiled, but now emits error C2065 for undeclared name 'allocator'.
// This should be declared as 'std::allocator<T*>' because the using directive nominating
// 'std' is not active at this point.
template <class T, class U = allocator<T*>>
class resource_list
{
};
namespace Gui
{
typedef resource_list<int> intlist;
}
Miglioramenti della conformità in Visual Studio 2022 versione 17.6
Visual Studio 2022 versione 17.6 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche del comportamento seguenti nel compilatore Microsoft C/C++.
Assegnazioni composte volatile
non più deprecate
C++20 deprecato applicando determinati operatori ai tipi qualificati con volatile
. Ad esempio, quando il codice seguente viene compilato con cl /std:c++20 /Wall test.cpp
:
void f(volatile int& expr)
{
++expr;
}
Il compilatore produce test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20
.
In C++20 gli operatori di assegnazione composta (operatori del formato @=
) sono stati deprecati. In C++23 gli operatori composti esclusi in C++20 non sono più deprecati. Ad esempio, in C++23 il codice seguente non genera un avviso, mentre in C++20:
void f(volatile int& e1, int e2)
{
e1 += e2;
}
Per altre informazioni su questa modifica, vedere CWG:2654
La riscrittura dell'uguaglianza nelle espressioni è minore di una modifica di rilievo (P2468R2)
In C++20 P2468R2 modificato il compilatore in modo da accettare codice come:
struct S
{
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} != S{};
Il compilatore accetta questo codice, il che significa che il compilatore è più rigoroso con il codice, ad esempio:
struct S
{
operator bool() const;
bool operator==(const S&);
};
bool b = S{} == S{};
La versione 17.5 del compilatore accetta questo programma. La versione 17.6 del compilatore lo rifiuta. Per correggerlo, aggiungere const
a operator==
per rimuovere l'ambiguità. In alternativa, aggiungere un oggetto corrispondente operator!=
alla definizione, come illustrato nell'esempio seguente:
struct S
{
operator bool() const;
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} == S{};
Le versioni del compilatore Microsoft C/C++ 17.5 e 17.6 accettano il programma precedente e le chiamate S::operator==
in entrambe le versioni.
Il modello di programmazione generale descritto in P2468R2 è che, se è presente un oggetto corrispondente operator!=
per un tipo, in genere elimina il comportamento di riscrittura. L'aggiunta di un corrispondente operator!=
è la correzione consigliata per il codice compilato in precedenza in C++17. Per altre informazioni, vedere Modello di programmazione.
Miglioramenti della conformità in Visual Studio 2022 versione 17.4
Visual Studio 2022 versione 17.4 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche di comportamento seguenti nel compilatore Microsoft C/C++.
Tipi sottostanti di senza ambito enum
senza tipo fisso
Nelle versioni di Visual Studio precedenti a Visual Studio 2022 versione 17.4, il compilatore C++ non ha determinato correttamente il tipo sottostante di un'enumerazione senza ambito senza tipo di base fisso. In /Zc:enumTypes
è ora possibile implementare correttamente il comportamento standard.
Lo standard C++ richiede che il tipo sottostante di un oggetto enum
sia sufficientemente grande da contenere tutti gli enumeratori in tale enum
. Gli enumeratori sufficientemente grandi possono impostare il tipo sottostante di enum
su unsigned int
, long long
o unsigned long long
. In precedenza, tali enum
tipi avevano sempre un tipo sottostante di int
nel compilatore Microsoft, indipendentemente dai valori dell'enumeratore.
Se abilitata, l'opzione /Zc:enumTypes
è una potenziale modifica di origine e di interruzione binaria. È disattivata per impostazione predefinita e non è abilitata da /permissive-
, perché la correzione potrebbe influire sulla compatibilità binaria. Alcuni tipi di enumerazione modificano le dimensioni quando la correzione conforme è abilitata. Alcune intestazioni di Windows SDK includono tali definizioni di enumerazione.
Esempio
enum Unsigned
{
A = 0xFFFFFFFF // Value 'A' does not fit in 'int'.
};
// Previously, failed this static_assert. Now passes with /Zc:enumTypes.
static_assert(std::is_same_v<std::underlying_type_t<Unsigned>, unsigned int>);
template <typename T>
void f(T x)
{
}
int main()
{
// Previously called f<int>, now calls f<unsigned int>.
f(+A);
}
// Previously this enum would have an underlying type of `int`, but Standard C++ requires this to have
// a 64-bit underlying type. Using /Zc:enumTypes changes the size of this enum from 4 to 8, which could
// impact binary compatibility with code compiled with an earlier compiler version or without the switch.
enum Changed
{
X = -1,
Y = 0xFFFFFFFF
};
Tipi di enumeratori all'interno di una enum
definizione senza tipo sottostante fisso
Nelle versioni di Visual Studio precedenti a Visual Studio 2022 versione 17.4, il compilatore C++ non ha modellato correttamente i tipi di enumeratori. Potrebbe presupporre un tipo non corretto nelle enumerazioni senza un tipo sottostante fisso prima della parentesi graffa di chiusura dell'enumerazione. In /Zc:enumTypes
il compilatore implementa ora correttamente il comportamento standard.
Lo standard C++ specifica che all'interno di una definizione di enumerazione senza tipo sottostante fisso, gli inizializzatori determinano i tipi di enumeratori. In alternativa, per gli enumeratori senza inizializzatore, per il tipo dell'enumeratore precedente (che rappresenta l'overflow). In precedenza, tali enumeratori venivano sempre assegnati al tipo dedotto dell'enumerazione, con un segnaposto per il tipo sottostante (in int
genere ).
Se abilitata, l'opzione /Zc:enumTypes
è una potenziale modifica di origine e di interruzione binaria. È disattivata per impostazione predefinita e non è abilitata da /permissive-
, perché la correzione potrebbe influire sulla compatibilità binaria. Alcuni tipi di enumerazione modificano le dimensioni quando la correzione conforme è abilitata. Alcune intestazioni di Windows SDK includono tali definizioni di enumerazione.
Esempio
enum Enum {
A = 'A',
B = sizeof(A)
};
static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes
In questo esempio l'enumeratore A
deve avere un tipo char
prima della parentesi graffa di chiusura dell'enumerazione, pertanto B
deve essere inizializzata usando sizeof(char)
. Prima della correzione, A
aveva un /Zc:enumTypes
tipo Enum
di enumerazione con un tipo int
sottostante dedotto ed B
è stato inizializzato usando sizeof(Enum)
, o 4.
Miglioramenti della conformità in Visual Studio 2022 versione 17.3
Visual Studio 2022 versione 17.3 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche del comportamento seguenti nel compilatore Microsoft C/C++.
C: Controllo della compatibilità dei modificatori migliorato tra puntatori
Il compilatore C non ha confrontato correttamente i modificatori tra puntatori, in particolare void*
. Questo difetto potrebbe comportare una diagnosi errata dell'incompatibilità tra e void*
e la compatibilità tra const int**
int* volatile*
e void*
.
Esempio
void fn(void* pv) { (pv); }
int main()
{
int t = 42;
int* pt = &t;
int* volatile * i = &pt;
fn(i); // Now raises C4090
const int** j = &pt;
fn(j); // No longer raises C4090
}
Miglioramenti della conformità in Visual Studio 2022 versione 17.2
Visual Studio 2022 versione 17.2 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche del comportamento seguenti nel compilatore Microsoft C/C++.
Avvisi di caratteri bidirezionali non terminati
Visual Studio 2022 versione 17.2 aggiunge l'avviso di livello 3 C5255 per i caratteri bidirezionali Unicode senza nome nei commenti e nelle stringhe. L'avviso risolve un problema di sicurezza descritto in Trojan Source: Invisible Vulnerabilities di Nicholas Boucher e Ross Anderson. Per altre informazioni sui caratteri bidirezionali Unicode, vedere Unicode Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM.For more information on Unicode bidirectional characters, see Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM.
Avviso C5255 indirizza solo i file che, dopo la conversione, contengono caratteri bidirezionali Unicode. Questo avviso si applica ai file UTF-8, UTF-16 e UTF-32, pertanto è necessario specificare la codifica di origine appropriata. Questa modifica è una modifica che causa un'interruzione di origine.
Esempio (prima/dopo)
Nelle versioni di Visual Studio precedenti a Visual Studio 2022 versione 17.2 un carattere bidirezionale non ha generato un avviso. Visual Studio 2022 versione 17.2 genera l'avviso C5255:
// bidi.cpp
int main() {
const char *access_level = "user";
// The following source line contains bidirectional Unicode characters equivalent to:
// if ( strcmp(access_level, "user\u202e \u2066// Check if admin \u2069 \u2066") ) {
// In most editors, it's rendered as:
// if ( strcmp(access_level, "user") ) { // Check if admin
if ( strcmp(access_level, "user // Check if admin ") ) {
printf("You are an admin.\n");
}
return 0;
}
/* build output
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+202e'
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+2066'
*/
from_chars()
float
tiebreaker
Visual Studio 2022 versione 17.2 corregge un bug nelle <charconv>
from_chars()
float
regole tiebreaker che generano risultati non corretti. Questo bug ha interessato stringhe decimali che si trovavano al punto medio esatto dei valori consecutivi float
, all'interno di un intervallo ristretto. I valori interessati più piccoli e più grandi sono rispettivamente 32768.009765625
e 131071.98828125
. La regola del tiebreaker voleva arrotondare a "even" e "even" era "down", ma l'implementazione arrotondata erroneamente "up" (double
non è stata influenzata. Per altre informazioni e dettagli sull'implementazione, vedere microsoft/STL#2366.
Questa modifica influisce sul comportamento di runtime nell'intervallo di casi specificato:
Esempio
// from_chars_float.cpp
#include <cassert>
#include <charconv>
#include <cstdio>
#include <string_view>
#include <system_error>
using namespace std;
int main() {
const double dbl = 32768.009765625;
const auto sv = "32768.009765625"sv;
float flt = 0.0f;
const auto result = from_chars(sv.data(), sv.data() + sv.size(), flt);
assert(result.ec == errc{});
printf("from_chars() returned: %.1000g\n", flt);
printf("This rounded %s.\n", flt < dbl ? "DOWN" : "UP");
}
Nelle versioni precedenti a Visual Studio 2022 versione 17.2:
C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.01171875
This rounded UP.
In Visual Studio 2022 versione 17.2 e successive:
C:\Temp>cl /EHsc /nologo /W4 /std:c++17 from_chars_float.cpp && from_chars_float
from_chars_float.cpp
from_chars() returned: 32768.0078125
This rounded DOWN.
/Zc:__STDC__
rende __STDC__
disponibile per C
Lo standard C richiede che un'implementazione C conforme definisca __STDC__
come 1
. A causa del comportamento di UCRT, che non espone le funzioni POSIX quando __STDC__
è 1
, non è possibile definire questa macro per C per impostazione predefinita senza introdurre modifiche di rilievo alle versioni del linguaggio stabile. Visual Studio 2022 versione 17.2 e successive aggiungono un'opzione /Zc:__STDC__
di conformità che definisce questa macro. Non esiste alcuna versione negativa dell'opzione. Attualmente, si prevede di usare questa opzione per impostazione predefinita per le versioni future di C.
Questa modifica è una modifica che causa un'interruzione di origine. Si applica quando la modalità C11 o C17 è abilitata (/std:c11
o /std:c17
) e /Zc:__STDC__
viene specificata.
Esempio
// test__STDC__.c
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
int main() {
#if __STDC__
int f = _open("file.txt", _O_RDONLY);
_close(f);
#else
int f = open("file.txt", O_RDONLY);
close(f);
#endif
}
/* Command line behavior
C:\Temp>cl /EHsc /W4 /Zc:__STDC__ test__STDC__.c && test__STDC__
*/
Avviso per parentesi graffe mancanti
Avviso C5246 segnala parentesi graffe mancanti durante l'inizializzazione aggregata di un oggetto secondario. Prima di Visual Studio 2022 versione 17.2, l'avviso non gestiva il caso di un anonimo struct
o union
.
Questa modifica è una modifica che causa un'interruzione di origine. Si applica quando è abilitato l'avviso C5246 disattivato per impostazione predefinita.
Esempio
In Visual Studio 2022 versione 17.2 e successive questo codice genera ora un errore:
struct S {
union {
float f[4];
double d[2];
};
};
void f()
{
S s = { 1.0f, 2.0f, 3.14f, 4.0f };
}
/* Command line behavior
cl /Wall /c t.cpp
t.cpp(10): warning C5246: 'anonymous struct or union': the initialization of a subobject should be wrapped in braces
*/
Per risolvere questo problema, aggiungere parentesi graffe all'inizializzatore:
void f()
{
S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Miglioramenti della conformità in Visual Studio 2022 versione 17.1
Visual Studio 2022 versione 17.1 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche del comportamento seguenti nel compilatore Microsoft C/C++.
Rilevare l'impostazione predefinita di acquisizione in formato non corretto nelle espressioni lambda non locali
Lo standard C++ consente solo a un'espressione lambda nell'ambito del blocco di avere un'impostazione predefinita di acquisizione. In Visual Studio 2022 versione 17.1 e successive, il compilatore rileva quando un'impostazione predefinita di acquisizione non è consentita in un'espressione lambda non locale. Genera un nuovo avviso di livello 4, C5253.
Questa modifica è una modifica che causa un'interruzione di origine. Si applica in qualsiasi modalità che usa il nuovo processore lambda: /Zc:lambda
, /std:c++20
o /std:c++latest
.
Esempio
In Visual Studio 2022 versione 17.1 questo codice genera ora un errore:
#pragma warning(error:5253)
auto incr = [=](int value) { return value + 1; };
// capture_default.cpp(3,14): error C5253: a nonlocal lambda cannot have a capture default
// auto incr = [=](int value) { return value + 1; };
// ^
Per risolvere questo problema, rimuovere l'impostazione predefinita di acquisizione:
#pragma warning(error:5253)
auto incr = [](int value) { return value + 1; };
C4028 è ora C4133 per le operazioni da funzione a puntatore
Prima di Visual Studio 2022 versione 17.1, il compilatore ha segnalato un messaggio di errore errato in determinati confronti puntatore a funzione nel codice C. Il messaggio non corretto è stato segnalato quando sono stati confrontati due puntatori a funzione con lo stesso numero di argomenti, ma tipi incompatibili. A questo punto, viene generato un avviso diverso che segnala l'incompatibilità da puntatore a funzione anziché la mancata corrispondenza dei parametri di funzione.
Questa modifica è una modifica che causa un'interruzione di origine. Si applica quando il codice viene compilato come C.
Esempio
int f1(int);
int f2(char*);
int main(void)
{
return (f1 == f2);
}
// Old warning:
// C4028: formal parameter 1 different from declaration
// New warning:
// C4113: 'int (__cdecl *)(char *)' differs in parameter lists from 'int (__cdecl *)(int)'
Errore in un oggetto non indipendente static_assert
In Visual Studio 2022 versione 17.1 e successive, se l'espressione associata a non static_assert
è un'espressione dipendente, il compilatore valuta l'espressione quando viene analizzata. Se l'espressione restituisce false
, il compilatore genera un errore. In precedenza, se l'oggetto static_assert
era all'interno del corpo di un modello di funzione (o all'interno del corpo di una funzione membro di un modello di classe), il compilatore non eseguirà questa analisi.
Questa modifica è una modifica che causa un'interruzione di origine. Si applica in qualsiasi modalità che implica /permissive-
o /Zc:static_assert
. Questa modifica del comportamento può essere disabilitata usando l'opzione del /Zc:static_assert-
compilatore.
Esempio
In Visual Studio 2022 versione 17.1 e successive questo codice genera ora un errore:
template<typename T>
void f()
{
static_assert(false, "BOOM!");
}
Per risolvere questo problema, rendere dipendente l'espressione. Ad esempio:
template<typename>
constexpr bool dependent_false = false;
template<typename T>
void f()
{
static_assert(dependent_false<T>, "BOOM!");
}
Con questa modifica, il compilatore genera un errore solo se viene creata un'istanza del modello f
di funzione.
Miglioramenti della conformità in Visual Studio 2022 versione 17.0
Visual Studio 2022 versione 17.0 contiene i miglioramenti di conformità, le correzioni di bug e le modifiche del comportamento seguenti nel compilatore Microsoft C/C++.
Avviso sulla larghezza del campo di bit per il tipo di enumerazione
Quando si dichiara un'istanza di un tipo di enumerazione come campo di bit, la larghezza del campo di bit deve contenere tutti i valori possibili dell'enumerazione. In caso contrario, il compilatore genera un messaggio di diagnostica. Si consideri questo esempio: Prendere in considerazione:
enum class E : unsigned { Zero, One, Two };
struct S {
E e : 1;
};
Un programmatore potrebbe aspettarsi che il membro S::e
della classe possa contenere uno qualsiasi dei valori denominati enum
in modo esplicito. Dato il numero di elementi di enumerazione, non è possibile. Il campo di bit non può coprire l'intervallo di valori forniti in modo esplicito di E
(concettualmente, il dominio di E
). Per risolvere il problema che la larghezza del campo di bit non è sufficiente per il dominio dell'enumerazione, viene aggiunto un avviso nuovo (disattivato per impostazione predefinita) a MSVC:
t.cpp(4,5): warning C5249: 'S::e' of type 'E' has named enumerators with values that cannot be represented in the given bit field width of '1'.
E e : 1;
^
t.cpp(1,38): note: see enumerator 'E::Two' with value '2'
enum class E : unsigned { Zero, One, Two };
^
Questo comportamento del compilatore è una modifica di origine e interruzione binaria che influisce su tutte le /std
modalità e /permissive
.
Errore nel confronto del puntatore ordinato rispetto nullptr
a o 0
Lo standard C++ ha consentito inavvertitamente un confronto del puntatore ordinato rispetto nullptr
a o 0. Ad esempio:
bool f(int *p)
{
return p >= 0;
}
Il documento WG21 N3478 ha rimosso questa supervisione. Questa modifica viene implementata in MSVC. Quando l'esempio viene compilato usando /permissive-
(e /diagnostics:caret
), genera l'errore seguente:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
return p >= 0;
^
Questo comportamento del compilatore è una modifica che causa un'interruzione binaria e di origine che influisce sul codice compilato usando /permissive-
in tutte le /std
modalità.