Condividi tramite


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 nella parte superiore di questo articolo.

Questo documento elenca le modifiche in Visual Studio 2022.

Per le modifiche apportate alle versioni precedenti di Visual Studio:

Versione Collegamento ai miglioramenti della conformità
2019 Miglioramenti della conformità C++ in Visual Studio 2019
2017 Miglioramenti della conformità di C++ in Visual Studio 2017
2003-2015 Visual C++: novità dalla versione 2003 alla 2015

Miglioramenti della conformità in Visual Studio 2022 versione 17.12

Visual Studio 2022 versione 17.12 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.12.

_com_ptr_t::operator bool() è ora esplicito

Si tratta di una modifica di rilievo di origine/binaria.

La conversione implicita in bool da _com_ptr_t istanze può essere sorprendente o causare errori del compilatore. Le funzioni di conversione implicite sono sconsigliate dalle linee guida di base C++(C.164) e _com_ptr_t contengono conversioni implicite in e bool Interface*. Queste due conversioni implicite possono causare ambiguità.

Per risolvere questo problema, la conversione in bool è ora esplicita. La conversione in Interface* è invariata.

Viene fornita una macro per rifiutare esplicitamente questo nuovo comportamento e ripristinare la conversione implicita precedente. Compilare con /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL per rifiutare esplicitamente questa modifica. È consigliabile modificare il codice in modo da non basarsi sulle conversioni implicite.

Ad esempio:

#include <comip.h>

template<class Iface>
using _com_ptr = _com_ptr_t<_com_IIID<Iface, &__uuidof(Iface)>>;

int main()
{
   _com_ptr<IUnknown> unk;
   if (unk) // Still valid
   { 
      // ...
   }
   bool b = unk; // Still valid.
   int v = unk; // Previously permitted, now emits C2240: cannot convert from '_com_ptr_t<_com_IIID<IUnknown,& _GUID_00000000_0000_0000_c000_000000000046>>' to 'int'
}

Le espressioni costanti non sono più sempre noexcept in modalità permissiva

Si tratta di una modifica di rilievo di origine/binaria.

Un'espressione costante era sempre noexcept, anche se implicava una chiamata di funzione a una funzione dichiarata con una specifica di eccezione potenzialmente generata. Questa formulazione è stata rimossa in C++17, anche se il compilatore Microsoft Visual C++ lo supporta ancora in modalità in /permissive tutte le versioni del linguaggio C++.

Questo /permissive comportamento della modalità viene rimosso. Le espressioni costanti non hanno più un comportamento implicito speciale.

L'identificatore noexcept per constexpr le funzioni viene ora rispettato in tutte le modalità. Questa modifica è necessaria per l'implementazione corretta delle soluzioni dei problemi principali successive che si basano sul comportamento standard noexcept .

Ad esempio:

constexpr int f(bool b) noexcept(false)
{ 
    if (b)
    {
        throw 1;
    }
    else
    {
        return 1;
    }
}

void g(bool b)
{
   noexcept(f(b)); // false. No change to behavior
   noexcept(f(true)); // false. No change to behavior
   noexcept(f(false)); // false. Was true in /permissive mode only in previous versions.
}

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.

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 a println(stdout);
  • println(FILE* stream); equivale a println(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 di 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 member1membro . 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 member1membro . 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:

typeof
typeof_unqual

Di seguito sono disponibili tutte le versioni del linguaggio C:

__typeof__
__typeof_unqual__

libreria standard C++

Funzionalità di C++23

  • formattable, range_format, format_kinde set_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 longo 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:enumTypesil 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 intgenere ).

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 intsottostante 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++20o /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à.

Vedi anche

Conformità del linguaggio Microsoft C/C++