Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Microsoft C/C++ i Visual Studio (MSVC) gör överensstämmelseförbättringar och felkorrigeringar i varje version. Den här artikeln listar de betydande förbättringarna först efter större utgåva, sedan efter version. Om du vill gå direkt till ändringarna för en viss version använder du I den här artikeln länkar överst i den här artikeln.
I det här dokumentet visas ändringarna i Visual Studio 2022.
För ändringar i tidigare versioner av Visual Studio:
| Utgåva | Länk för konformitetsförbättringar | 
|---|---|
| 2019 | C++-efterlevnadsförbättringar i Visual Studio 2019 | 
| 2017 | förbättringar av C++-överensstämmelse i Visual Studio 2017 | 
| 2003-2015 | Visual C++ Nyheter 2003 till och med 2015 | 
Överensstämmelseförbättringar i Visual Studio 2022 version 17.14
Visual Studio 2022 version 17.14 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
Anpassningsförbättringar
- Standardbibliotekshärdning (P3471R4) omvandlar vissa instanser av odefinierat beteende i standardbiblioteket till ett anrop till __fastfail. Av som standard. Definiera _MSVC_STL_HARDENING=1för hela projektet för att aktivera.
Förbättrat beteende
- Implementerade "destructor tombstones" för att minimera misstag med användning efter fri användning. Av som standard. Definiera _MSVC_STL_DESTRUCTOR_TOMBSTONES=1för hela projektet för att aktivera.
Felkorrigeringar
- Felaktiga kompilatorfel vid användning av - <format>i ett CUDA-projekt har åtgärdats.
- Ett kompilatorproblem har åtgärdats där adressen till en lokal variabel kan "läcka" under - constexprutvärderingen. Till exempel:- const unsigned & func() { const int x = 0; constexpr const unsigned & r1 = x; // Previously accepted, now an error return r1; } auto r = func(); // Previously, the local address leaked- Exempel nr 2 - #include <initializer_list> void test() { constexpr std::initializer_list<int> xs { 1, 2, 3 }; // Previously accepted, now an error static constexpr std::initializer_list<int> ys { 1, 2, 3 }; // Correct usage - note use of static }
- Kod som kompileras med - /permissive-accepterar inte längre en kombination av- friendoch- staticpå en deklaration. Korrigeringen är vanligtvis att ta bort- staticfrån deklarationen. Till exempel:- struct S { friend static void f(); // Previously accepted, now emits error C2440: 'static' cannot be used with 'friend' };
- Referensbindning till volatile-kvalificerade typer har åtgärdats vid hänvisning till en bas- eller härledd klass. Till exempel: - struct A {}; struct B : public A {}; void f(A&); // 1 void f(const volatile A&); // 2 f(B{}); // Previously called 2. This is ill-formed under /permissive- or /Zc:referenceBinding. Chooses 1 if relaxed reference binding rules are enabled.
En djupgående sammanfattning av ändringar som gjorts i standardmallbiblioteket, inklusive anpassningsändringar, felkorrigeringar och prestandaförbättringar, finns i STL Changelog VS 2022 17.14.
Anpassningsförbättringar i Visual Studio 2022 version 17.13
Visual Studio 2022 version 17.13 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
En djupgående sammanfattning av ändringar som gjorts i standardmallbiblioteket, inklusive överensstämmelseändringar, felkorrigeringar och prestandaförbättringar, finns i STL Changelog VS 2022 17.13.
Argumentberoende sökning (ADL)
Språkkonstruktioner som intervall för och strukturerade bindningar har särskilda argumentberoende uppslagsregler för vissa identifierare, till exempel begin, endeller get. Tidigare inkluderade uppslagningen kandidater från namnområdet std, även om namnområdet std inte ingår i den vanliga uppsättningen av associerade namnområden för argumentberoende uppslagning.
Program som introducerade deklarationer till std för dessa konstruktioner kompileras inte längre. I stället bör deklarationerna finnas i ett normalt associerat namnområde för de typer som ingår (eventuellt inklusive det globala namnområdet).
template <typename T>
struct Foo {};
namespace std
{
    // To correct the program, move these declarations from std to the global namespace
    template <typename T>
    T* begin(Foo<T>& f);
    template <typename T>
    T* end(Foo<T>& f);
}
void f(Foo<int> foo)
{
   for (auto x : foo) // Previously compiled. Now emits error C3312: no callable 'begin' function found for type 'Foo<int>'
   {
      ...
   }
}
Det går inte att ändra implementeringsreserverade makron
Tidigare tillät kompilatorn att ändra eller odefiniera vissa implementeringsbaserade makron, till exempel _MSC_EXTENSIONS. Om du ändrar definitionen av vissa makron kan det leda till odefinierat beteende.
Om du försöker ändra eller avdefiniera vissa reserverade makronamn resulterar det nu i nivå 1-varningen C5308. I /permissive- läge behandlas varningen som ett fel.
#undef _MSC_EXTENSIONS // Warning C5308: Modifying reserved macro name `_MSC_EXTENSIONS` may cause undefined behavior
Anpassningsförbättringar i Visual Studio 2022 version 17.12
Visual Studio 2022 version 17.12 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
En djupgående sammanfattning av ändringar som gjorts i standardmallbiblioteket, inklusive anpassningsändringar, felkorrigeringar och prestandaförbättringar, finns i STL Changelog VS 2022 17.12.
              _com_ptr_t::operator bool() är nu explicit
Det här är en förändring som bryter kompatibilitet i käll-/binärkod.
Den implicita konverteringen till bool från _com_ptr_t instanser kan vara överraskande eller leda till kompilatorfel. 
              C.164: Undvik implicita konverteringsoperatorer i C++ Core Guidelines avråder från implicita konverteringsfunktioner. Och _com_ptr_t innehöll implicita konverteringar till både bool och Interface*. Dessa två implicita konverteringar kan leda till tvetydigheter.
För att åtgärda detta är konverteringen till bool nu explicit. Konverteringen till Interface* är oförändrad.
Ett makro tillhandahålls för att välja bort det här nya beteendet och återställa den tidigare implicita konverteringen. Kompilera med /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL för att välja bort den här ändringen. Vi rekommenderar att du ändrar koden så att den inte förlitar sig på implicita konverteringar.
Till exempel:
#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'
}
Konstanta uttryck är inte längre alltid noexcept i tillåtande läge
Det här är en förändring som bryter kompatibilitet i käll-/binärkod.
Ett konstant uttryck var alltid noexcept, även om det involverade ett funktionsanrop till en funktion som deklarerats med en potentiellt utlösande undantagsspecifikation. Den här formuleringen togs bort i C++17, även om Microsoft Visual C++-kompilatorn fortfarande stödde den i /permissive läge i alla C++-språkversioner.
Det här beteendet för /permissive läge tas bort. Konstanta uttryck har inte längre något speciellt implicit beteende.
              noexcept-specifieraren på constexpr-funktioner respekteras nu i alla lägen. Den här ändringen krävs för korrekt implementering av senare grundläggande problemlösningar som förlitar sig på standardbeteendet noexcept.
Till exempel:
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.
}
Anpassningsförbättringar i Visual Studio 2022 version 17.11
Visual Studio 2022 version 17.11 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
En djupgående sammanfattning av ändringar som gjorts i standardmallbiblioteket, inklusive överensstämmelseändringar, felkorrigeringar och prestandaförbättringar, finns i STL Changelog VS 2022 17.11.
Skriv ut tomma rader med println
Per P3142R0är det nu enkelt att generera en tom rad med println. Den här funktionen är tillgänglig när du kompilerar med /std:c++latest.
Innan den här ändringen skrev du: println(""); Nu skriver du: println();.
- 
              println();motsvararprintln(stdout);
- 
              println(FILE* stream);motsvararprintln(stream, "\n");
Implementerad range_formatter
Enligt P2286R8är range_formatter nu implementerad. Den här funktionen är tillgänglig när du kompilerar med /std:c++latest.
Anpassningsförbättringar i Visual Studio 2022 version 17.10
Visual Studio 2022 version 17.10 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
En djupgående sammanfattning av ändringar som gjorts i standardmallbiblioteket, inklusive anpassningsändringar, felkorrigeringar och prestandaförbättringar, finns i STL Changelog VS 2022 17.10.
Konverteringsoperatorspecialisering med uttryckligen angiven returtyp
Kompilatorn specialiserade felaktigt konverteringsoperatorer i vissa fall, vilket kunde leda till en returtyp som inte stämmer överens. Dessa ogiltiga specialiseringar sker inte längre. Det här är en källkodsändring som bryter kompatibilitet.
// 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
}
Stöd för #elifdef och #elifndef har lagts till
Stöd har lagts till för WG21 P2334R1 (C++23) och WG14 N2645 (C++23) som införde #elifdef- och #elifndef förprocessordirektiv.
Kräver /std:clatest eller /std:c++latest.
Före:
#ifdef __cplusplus
  #include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif
Efter:
#ifdef __cplusplus
  #include <atomic>
#elifndef __STDC_NO_ATOMICS__
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif
Tillämpning av _Alignas på en strukturerad typ i C
Gäller för C-språket (C17 och senare). Har också lagts till i Microsoft Visual Studio 17.9
I versioner av Visual C++ före Visual Studio 2022 version 17.9, om _Alignas-specificeraren visades bredvid en strukturerad typ i en deklaration, tillämpades den inte korrekt enligt ISO-C Standard.
// 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");
Enligt ISO-C Standard bör den här koden kompileras utan att static_assert generera en diagnostik.
              _Alignas-direktivet gäller endast för medlemsvariabeln member1. Den får inte ändra justeringen för struct Inner. Innan Visual Studio 17.9.1 genererades dock det diagnostiska meddelandet "felaktiga justeringen". Kompilatorn justerade member2 till en förskjutning på 32 byte inom den struct Outer typen.
Det här är en binär brytande ändring, så en varning ges nu när denna ändring börjar gälla. Varning C5274 genereras nu på varningsnivå 1 för föregående exempel:  warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).
I tidigare versioner av Visual Studio, när _Alignas-specificeraren visades bredvid en anonym typdeklaration, ignorerades den.
// 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");
Tidigare misslyckades båda static_assert-instruktioner vid kompilering av den här koden. Nu kompilerar koden, men genererar följande nivå 1-varningar:
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)
Om du vill hämta det tidigare beteendet ersätter du _Alignas(N) med __declspec(align(N)). Till skillnad från _Alignasgäller declspec(align) för typen.
Förbättrad varning C4706
Det här är en källkodsändring som bryter kompatibilitet. Tidigare identifierade kompilatorn inte konventionen att omsluta en tilldelning inom parenteser, om tilldelningen var avsedd, för att förhindra varning C4706 om tilldelning inom ett villkorsuttryck. Kompilatorn identifierar nu parenteserna och undertrycker varningen.
#pragma warning(error: 4706)
struct S
{
   auto mf()
   {
      if (value = 9)
         return value + 4;
      else
         return value;
   }
   int value = 9;
};
Kompilatorn genererar nu även varningen i fall där funktionen inte refereras till. Tidigare, eftersom mf är en infogad funktion som inte refereras till, har varning C4706 inte genererats för den här koden. Nu genereras varningen:
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
För att åtgärda den här varningen, använd antingen en likhetsoperator, value == 9, om det var avsett. Om tilldelningen är avsedd, omslut den med parenteser, (value = 9). Annars tar du bort funktionen eftersom den är orefererad.
Anpassningsförbättringar i Visual Studio 2022 version 17.9
Visual Studio 2022 version 17.9 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
En bredare sammanfattning av ändringar som gjorts i standardmallbiblioteket finns i STL Changelog VS 2022 17.9.
Tillämpning av _Alignas på en strukturerad typ i C
I versioner av Visual C++ före Visual Studio 2022 version 17.9, när _Alignas visades bredvid en strukturtyp i en deklaration, tillämpades den inte korrekt enligt ISO-C Standard. Till exempel:
// 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");
Enligt ISO-C Standard bör den här koden kompileras utan att static_assert genererar en diagnostik. 
              _Alignas-direktivet gäller endast för medlemsvariabeln member1. Den får inte ändra justeringen för struct Inner. Innan version 17.9.1 av Visual Studio släpptes, emitterades dock diagnostiken "felaktig justering". Kompilatorn justerade member2 till en förskjutning på 32 byte inom struct Outer.
Att åtgärda detta är en binär förändring som bryter kompatibiliteten, så när denna beteendeförändring tillämpas genereras en varning. För föregående kod, Varning C5274, "_Alignas gäller inte längre för typen "Inre" (gäller endast deklarerade dataobjekt)" genereras nu på varningsnivå 1.
I tidigare versioner av Visual Studio ignorerades _Alignas när den visades bredvid en anonym typdeklaration. Till exempel:
// 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");
Tidigare misslyckades båda static_assert-instruktioner vid kompilering av den här koden. Koden kompileras nu, men med följande nivå 1-varningar:
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)
Om du vill ha det tidigare beteendet ersätter du _Alignas(N) med __declspec(align(N)). Till skillnad från _Alignaskan declspec(align) tillämpas på en typ.
              __VA_OPT__ är aktiverat som ett tillägg under /Zc:preprocessor
              __VA_OPT__ lades till i C++20 och C23. Innan dess tillägg fanns det inte ett standardiserat sätt att utelämna ett kommatecken i ett variadiskt makro. För att ge bättre bakåtkompatibilitet aktiveras __VA_OPT__ under den tokenbaserade förprocessorn /Zc:preprocessor i alla språkversioner.
Detta kompileras till exempel nu utan fel:
#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")
C23-språk
För C23 är följande tillgängliga när du använder /std:clatest-kompilatorväxeln:
Följande är tillgängliga för alla C-språkversioner:
C++-standardbibliotek
C++23-funktioner
- 
              formattable,range_format,format_kindochset_debug_format()som en del av P2286R8 formateringsintervall
- 
              <mdspan>per P0009R18 och efterföljande formuleringsändringar som införlivades i C++23-standard.
- 
              format()pekare per P2510R3.
Anpassningsförbättringar i Visual Studio 2022 version 17.8
Visual Studio 2022 version 17.8 innehåller följande överensstämmelseförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
              /FU genererar ett fel
C-kompilatorn brukade acceptera alternativet /FU, även om den inte har haft stöd för hanterad kompilering på ett tag nu. Det har nu uppstått ett fel. Projekt som klarar det här alternativet behöver endast begränsa det till C++/CLI-projekt.
C++-standardbibliotek
De C++23 namngivna modulerna std och std.compat är nu tillgängliga vid kompilering med /std:c++20.
En bredare sammanfattning av ändringar som gjorts i C++-standardbiblioteket finns i STL Changelog VS 2022 17.8.
Anpassningsförbättringar i Visual Studio 2022 version 17.7
Visual Studio 2022 version 17.7 innehåller följande markerade efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
              /std:clatest har lagts till i C-kompilatorn
Den här växeln fungerar som växeln /std:c++latest för C++-kompilatorn. Växeln aktiverar alla för närvarande implementerade kompilator- och standardbiblioteksfunktioner som föreslås för nästa utkast till C-standard, samt vissa pågående och experimentella funktioner.
C++-standardbibliotek
Nu stöds <print>-biblioteket. Se P2093R14 Formaterade utdata.
Har implementerats views::cartesian_product.
En bredare sammanfattning av ändringar som gjorts i standardmallbiblioteket finns i STL Changelog VS 2022 17.7.
              using överensstämmelse
Tidigare kunde using-direktivet göra så att namn från använda namnområden förblir synliga när de inte borde göra det. Detta kan orsaka okvalificerad namnsökning för att hitta ett namn i ett namnområde även om det inte finns någon aktiv using direktiv.
Här följer några exempel på det nya och gamla beteendet.
Referenser i de följande kommentarerna till "(1)" avser anropet till f<K>(t) i namnområdet 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>()); 
    } 
} 
Samma underliggande problem kan orsaka att kod som tidigare kompilerats nu avvisas:
#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;
}
Anpassningsförbättringar i Visual Studio 2022 version 17.6
Visual Studio 2022 version 17.6 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
Sammansatta volatile tilldelningar är inte längre inaktuella
C++20 har gjort det föråldrat att tillämpa vissa operatorer på typer som är kvalificerade med volatile. Till exempel när följande kod kompileras med cl /std:c++20 /Wall test.cpp:
void f(volatile int& expr)
{
   ++expr;
}
Kompilatorn producerar test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20.
I C++20 blev sammansatta tilldelningsoperatorer (operatorer i formuläret @=) inaktuella. I C++23 är sammansatta operatorer som undantas i C++20 inte längre inaktuella. I C++23 ger till exempel inte följande kod någon varning, medan den gör det i C++20:
void f(volatile int& e1, int e2)
{
   e1 += e2;
}
Mer information om den här ändringen finns i CWG:2654
Att skriva om likhet i uttryck är mindre av en brytande ändring (P2468R2)
I C++20 ändrade P2468R2 kompilatorn så att den accepterade kod som:
struct S
{
    bool operator==(const S&);
    bool operator!=(const S&);
};
bool b = S{} != S{};
Kompilatorn accepterar den här koden, vilket innebär att kompilatorn är striktare med kod som:
struct S
{
  operator bool() const;
  bool operator==(const S&);
};
bool b = S{} == S{};
Version 17.5 av kompilatorn godkänner det här programmet. Version 17.6 av kompilatorn avvisar den. Åtgärda problemet genom att lägga till const i operator== för att ta bort tvetydigheten. Du kan också lägga till en motsvarande operator!= i definitionen enligt följande exempel:
struct S
{
  operator bool() const;
  bool operator==(const S&);
  bool operator!=(const S&);
};
bool b = S{} == S{};
Microsoft C/C++-kompilatorversionerna 17.5 och 17.6 accepterar det tidigare programmet och anropar S::operator== i båda versionerna.
Den allmänna programmeringsmodellen som beskrivs i P2468R2 är att om det finns en motsvarande operator!= för en typ, undertrycks vanligtvis omskrivningsbeteendet. Att lägga till en motsvarande operator!= är den föreslagna korrigeringen för kod som tidigare kompilerats i C++17. Mer information finns i Programmeringsmodell.
Anpassningsförbättringar i Visual Studio 2022 version 17.4
Visual Studio 2022 version 17.4 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
Underliggande typer av odefinierad omfattning för enum utan fast typ
I versioner av Visual Studio före Visual Studio 2022 version 17.4 fastställde C++-kompilatorn inte korrekt den underliggande typen av en oscoped uppräkning utan fast bastyp. Under /Zc:enumTypesimplementerar vi nu standardbeteendet korrekt.
C++ Standard kräver att den underliggande typen av en enum är tillräckligt stor för att rymma alla uppräknare i den enum. Tillräckligt stora uppräknare kan ange den underliggande typen av enum till unsigned int, long longeller unsigned long long. Tidigare hade sådana enum typer alltid en underliggande typ av int i Microsoft-kompilatorn, oavsett uppräkningsvärden.
När /Zc:enumTypes-alternativet är aktiverat kan det utgöra en potentiell källa till ändringar som bryter binär och källkompatibilitet. Den är inaktiverad som standard och aktiveras inte av /permissive-eftersom korrigeringen kan påverka binär kompatibilitet. Vissa uppräkningstyper ändrar storlek när den kompatibla korrigeringen är aktiverad. Vissa Windows SDK-huvuden innehåller sådana uppräkningsdefinitioner.
Exempel
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
};
Typer av uppräknare inom en enum definition utan fast underliggande typ
I versioner av Visual Studio före Visual Studio 2022 version 17.4 modellerade C++-kompilatorn inte uppräkningstyperna korrekt. Det kan anta en felaktig typ i uppräkningar utan en fast underliggande typ före den avslutande klammerparentesen i uppräkningen. Under /Zc:enumTypesimplementerar kompilatorn nu standardbeteendet korrekt.
C++-standarden anger att inom en uppräkningsdefinition utan en fast underliggande typ, bestämmer initialisatorer typerna för uppräknarna. Eller, för uppräkningsvariabler utan initierare, av typen av den tidigare uppräkningsvariabeln (med hänsyn till överflöd). Tidigare fick sådana uppräknare alltid den härledde typen av uppräkning, med platshållare för den underliggande typen (vanligtvis int).
När /Zc:enumTypes-alternativet är aktiverat kan det utgöra en potentiell källa till ändringar som bryter binär och källkompatibilitet. Den är inaktiverad som standard och aktiveras inte av /permissive-eftersom korrigeringen kan påverka binär kompatibilitet. Vissa uppräkningstyper ändrar storlek när den kompatibla korrigeringen är aktiverad. Vissa Windows SDK-huvuden innehåller sådana uppräkningsdefinitioner.
Exempel
enum Enum {
    A = 'A',
    B = sizeof(A)
};
static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes
I det här exemplet bör uppräkningsverktyget A ha typ char innan uppräkningens avslutande klammerparentes, så B bör initieras med hjälp av sizeof(char). Innan /Zc:enumTypes korrigeringen hade A uppräkningstyp Enum med en härledd underliggande typ intoch B initierades med sizeof(Enum)eller 4.
Anpassningsförbättringar i Visual Studio 2022 version 17.3
Visual Studio 2022 version 17.3 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
C: Förbättrad kompatibilitetskontroll av modifierare mellan pekare
C-kompilatorn jämförde inte modifierare mellan pekare korrekt, särskilt void*. Den här defekten kan leda till felaktig diagnos av inkompatibilitet mellan const int** och void* och kompatibilitet mellan int* volatile* och void*.
Exempel
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
}
Anpassningsförbättringar i Visual Studio 2022 version 17.2
Visual Studio 2022 version 17.2 innehåller följande överensstämmelseförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
Obestämda dubbelriktade teckenvarningar
Visual Studio 2022 version 17.2 lägger till nivå 3-varning C5255 för obestämda unicode-dubbelriktade tecken i kommentarer och strängar. Varningen tar upp ett säkerhetsproblem som beskrivs i Trojan Source: Osynliga sårbarheter av Nicholas Boucher och Ross Anderson. Mer information om dubbelriktade Unicode-tecken finns i Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM.
Varning C5255 adresserar endast filer som efter konverteringen innehåller unicode-dubbelriktade tecken. Den här varningen gäller för UTF-8-, UTF-16- och UTF-32-filer, så rätt källkodning måste anges. Den här ändringen är en källbrytande ändring.
Exempel (före/efter)
I versioner av Visual Studio före Visual Studio 2022 version 17.2 gav ett oavslutat dubbelriktat tecken ingen varning. Visual Studio 2022 version 17.2 ger varning 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 skiljebreak
Visual Studio 2022 version 17.2 åtgärdar en bugg i <charconv>from_chars()float tiebreaker-regler som gav felaktiga resultat. Den här buggen påverkade decimalsträngar som låg vid den exakta mittpunkten för efterföljande float värden inom ett smalt intervall. (De minsta och största berörda värdena var 32768.009765625 respektive 131071.98828125.) Tiebreaker-regeln ville avrunda till "jämn" och "till och med" råkade vara "nere", men implementeringen avrundade felaktigt "upp" (double påverkades inte.) Mer information och implementeringsinformation finns i microsoft/STL#2366.
Den här ändringen påverkar körningsbeteendet i det angivna intervallet av ärenden:
Exempel
// 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");
}
I versioner före Visual Studio 2022 version 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.
I Visual Studio 2022 version 17.2 och efter:
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__ gör __STDC__ tillgängliga för C
C-standarden kräver att en överensstämmande C-implementering definierar __STDC__ som 1. På grund av beteendet för UCRT, som inte exponerar POSIX-funktioner när __STDC__ är 1, är det inte möjligt att definiera det här makrot för C som standard utan att införa icke-bakåtkompatibla ändringar i stabila språkversioner. Visual Studio 2022 version 17.2 och senare lägga till ett överensstämmelsealternativ /Zc:__STDC__ som definierar makrot. Det finns ingen negativ version av alternativet. För närvarande planerar vi att använda det här alternativet som standard för framtida versioner av C.
Den här ändringen är en källbrytande ändring. Det gäller när C11- eller C17-läge är aktiverat (/std:c11 eller /std:c17) och /Zc:__STDC__ anges.
Exempel
// 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__
*/
Varning för saknade klammerparenteser
Varning C5246 rapporterar saknade klamrar vid aggregerad initiering av ett delobjekt. Före Visual Studio 2022 version 17.2 hanterade varningen inte fallet med en anonym struct eller union.
Den här ändringen är en källbrytande ändring. Det gäller när den off-by-default-varningen C5246 är aktiverad.
Exempel
I Visual Studio 2022 version 17.2 och senare orsakar den här koden nu ett fel:
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
*/
Lös problemet genom att lägga till klammerparenteser i initieraren:
void f()
{
   S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Anpassningsförbättringar i Visual Studio 2022 version 17.1
Visual Studio 2022 version 17.1 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
Identifiera felaktigt formaterad fångststandard i icke-lokala lambda-uttryck
C++ Standard tillåter endast att ett lambda-uttryck i blockomfånget har en capture-default. I Visual Studio 2022 version 17.1 och senare identifierar kompilatorn när en avbildningsstandard inte tillåts i ett icke-lokaliserat lambda-uttryck. Den avger en ny nivå 4-varning, C5253.
Den här ändringen är en källbrytande ändring. Det gäller i alla lägen som använder den nya lambda-processorn: /Zc:lambda, /std:c++20eller /std:c++latest.
Exempel
I Visual Studio 2022 version 17.1 utlöser den här koden nu ett fel:
#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; };
//              ^
Åtgärda det här problemet genom att ta bort standardinställningen för infångning:
#pragma warning(error:5253)
auto incr = [](int value) { return value + 1; };
C4028 är nu C4133 för funktion till pekare-operationer
Före Visual Studio 2022 version 17.1 rapporterade kompilatorn ett felaktigt felmeddelande om vissa jämförelsen mellan pekare och funktioner i C-kod. Det felaktiga meddelandet rapporterades när du jämförde två funktionspekare som hade samma argumentantal men inkompatibla typer. Nu utfärdar vi en annan varning som klagar på inkompatibilitet mellan pekare och funktion i stället för felmatchning av funktionsparametrar.
Den här ändringen är en källbrytande ändring. Det gäller när kod kompileras som C.
Exempel
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)'
Fel på ett icke-beroende static_assert
I Visual Studio 2022 version 17.1 och senare, om uttrycket som är associerat med en static_assert inte är ett beroende uttryck, utvärderar kompilatorn uttrycket när det parsas. Om uttrycket utvärderas till falsegenererar kompilatorn ett fel. Om static_assert tidigare fanns i brödtexten i en funktionsmall (eller i brödtexten för en medlemsfunktion i en klassmall) skulle kompilatorn inte utföra den här analysen.
Den här ändringen är en källbrytande ändring. Det gäller i alla lägen som innebär /permissive- eller /Zc:static_assert. Den här beteendeändringen kan inaktiveras med hjälp av /Zc:static_assert- kompilatoralternativet.
Exempel
I Visual Studio 2022 version 17.1 och senare orsakar den här koden nu ett fel:
template<typename T>
void f()
{
   static_assert(false, "BOOM!");
}
Åtgärda problemet genom att göra uttrycket beroende. Till exempel:
template<typename>
constexpr bool dependent_false = false;
template<typename T>
void f()
{
   static_assert(dependent_false<T>, "BOOM!");
}
Med den här ändringen genererar kompilatorn bara ett fel om funktionsmallen f instansieras.
Anpassningsförbättringar i Visual Studio 2022 version 17.0
Visual Studio 2022 version 17.0 innehåller följande efterlevnadsförbättringar, felkorrigeringar och beteendeändringar i Microsoft C/C++-kompilatorn.
Varning om bitfältsbredd för uppräkningstyp
När du deklarerar en instans av en uppräkningstyp som bitfält måste bitfältets bredd rymma alla möjliga värden för uppräkningen. Annars utfärdar kompilatorn ett diagnostikmeddelande. Tänk på det här exemplet: Överväg:
enum class E : unsigned { Zero, One, Two };
struct S {
  E e : 1;
};
En programmerare kan förvänta sig att klassmedlemmen S::e kan innehålla något av de explicit namngivna enum värdena. Med tanke på antalet uppräkningselement är det inte möjligt. Bitfältet kan inte täcka intervallet med explicit angivna värden för E (konceptuellt domänen för E). För att åtgärda problemet med att bitfältsbredden inte är tillräckligt stor för uppräkningsdomänen läggs en ny varning (av som standard) till i 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 };
                                     ^
Det här kompilatorbeteendet är en käll- och binär icke-bakåtkompatibel ändring som påverkar alla /std och /permissive lägen.
Fel vid jämförelse av ordnade pekare mot nullptr eller 0
C++ Standard tillät oavsiktligt en ordnad pekarjämförelse mot nullptr eller 0. Till exempel:
bool f(int *p)
{
   return p >= 0;
}
WG21 paper N3478 rättade till denna förbiseende. Den här ändringen implementeras i MSVC. När exemplet kompileras med hjälp av /permissive- (och /diagnostics:caret) genererar det följande fel:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
    return p >= 0;
             ^
Det här kompilatorbeteendet är en käll- och binär brytändring som påverkar kod som kompilerats med hjälp av /permissive- i alla /std kompilatorlägen.