Verbesserungen der C++-Konformität, Behavior Changes und Fehlerbehebungen in Visual Studio 2022

Microsoft C/C++ in Visual Studio (MSVC) nimmt bei jedem Release Verbesserungen bei der Konformität mit Standards sowie bei Fehlerbehebungen vor. In diesem Artikel werden die wesentlichen Verbesserungen nach Hauptrelease und dann nach Versionen aufgelistet. Um direkt zu den Änderungen für eine bestimmte Version zu springen, verwenden Sie die Links in diesem Artikel oben in diesem Artikel .

In diesem Dokument werden die Änderungen in Visual Studio 2022 aufgelistet.

Für Änderungen in früheren Versionen von Visual Studio:

Version Link "Konformitätsverbesserungen"
2019 Verbesserungen der C++-Konformität in Visual Studio 2019
2017 Verbesserungen bei der Übereinstimmung mit C++-Standards in Visual C++ 2017
2003-2015 Visual C++: Neuerungen von 2003 bis 2015

Konformitätsverbesserungen in Visual Studio 2022, Version 17.12

Visual Studio 2022, Version 17.12, enthält die folgenden Konformitätsverbesserungen, Fehlerkorrekturen und Verhaltensänderungen im Microsoft C/C++-Compiler.

Eine ausführliche Zusammenfassung der Änderungen, die an der Standardvorlagenbibliothek vorgenommen wurden, einschließlich Konformitätsänderungen, Fehlerbehebungen und Leistungsverbesserungen, finden Sie unter STL Changelog VS 2022 17.12.

_com_ptr_t::operator bool() ist jetzt explizit

Dies ist eine Quell-/Binäre Unterbrechungsänderung.

Die implizite Konvertierung bool von _com_ptr_t Instanzen kann überraschend sein oder zu Compilerfehlern führen. Implizite Konvertierungsfunktionen werden von den C++-Kernrichtlinien (C.164) abgeraten und _com_ptr_t enthalten implizite Konvertierungen in beide bool und Interface*. Diese beiden impliziten Konvertierungen können zu Mehrdeutigkeiten führen.

Um dies zu beheben, ist die Konvertierung bool jetzt explizit. Die Konvertierung in Interface* ist unverändert.

Ein Makro wird bereitgestellt, um dieses neue Verhalten zu deaktivieren und die vorherige implizite Konvertierung wiederherzustellen. Kompilieren Sie /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL diese Änderung, um diese Änderung abzumelden. Es wird empfohlen, den Code so zu ändern, dass er nicht auf implizite Konvertierungen angewiesen ist.

Zum Beispiel:

#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'
}

Konstantenausdrücke befinden sich nicht mehr immer noexcept im zulässigen Modus.

Dies ist eine Quell-/Binäre Unterbrechungsänderung.

Ein konstanter Ausdruck war immer noexcept, auch wenn ein Funktionsaufruf an eine Funktion beteiligt war, die mit einer potenziell auslösenden Ausnahmespezifikation deklariert wurde. Diese Formulierung wurde in C++17 entfernt, obwohl der Microsoft Visual C++-Compiler sie weiterhin im /permissive Modus in allen C++-Sprachversionen unterstützt hat.

Dieses /permissive Modusverhalten wird entfernt. Konstantenausdrücke erhalten kein spezielles implizites Verhalten mehr.

Der noexcept Bezeichner für constexpr Funktionen wird jetzt in allen Modi berücksichtigt. Diese Änderung ist für die korrekte Implementierung späterer Kernproblemauflösungen erforderlich, die auf dem Standardverhalten noexcept basieren.

Zum Beispiel:

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.
}

Konformitätsverbesserungen in Visual Studio 2022, Version 17.11

Visual Studio 2022, Version 17.11, enthält die folgenden Konformitätsverbesserungen, Fehlerkorrekturen und Verhaltensänderungen im Microsoft C/C++-Compiler.

Eine ausführliche Zusammenfassung der Änderungen, die an der Standardvorlagenbibliothek vorgenommen wurden, einschließlich Konformitätsänderungen, Fehlerbehebungen und Leistungsverbesserungen, finden Sie unter STL Changelog VS 2022 17.11.

Pro P3142R0 ist es jetzt einfach, eine leere Zeile mit println. Dieses Feature ist beim Kompilieren mit /std:c++latestverfügbar. Vor dieser Änderung haben Sie geschrieben: Jetzt schreiben Sie: println(""); println();.

  • println(); entspricht println(stdout);
  • println(FILE* stream); entspricht println(stream, "\n");

Umgesetzt range_formatter

Pro P2286R8range_formatter wird jetzt implementiert. Dieses Feature ist beim Kompilieren mit /std:c++latestverfügbar.

Verbesserungen der Konformität in Visual Studio 2022, Version 17.10

Visual Studio 2022, Version 17.10, enthält die folgenden Konformitätsverbesserungen, Fehlerkorrekturen und Verhaltensänderungen im Microsoft C/C++-Compiler.

Eine ausführliche Zusammenfassung der Änderungen an der Standardvorlagenbibliothek, einschließlich Konformitätsänderungen, Fehlerbehebungen und Leistungsverbesserungen, finden Sie unter STL-Änderungsprotokoll VS 2022 17.10.

Spezialisierung des Konvertierungsoperators mit explizit angegebenem Rückgabetyp

Der Compiler spezialisierte Konvertierungsoperatoren in einigen Fällen falsch, was zu einem nicht übereinstimmenden Rückgabetyp führen konnte. Diese ungültigen Spezialisierungen gibt es nicht mehr. Dabei handelt es sich um einen Breaking Change im Quellcode.

// 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
}

Die Unterstützung für #elifdef und #elifndef wurde hinzugefügt.

Unterstützung für WG21 P2334R1 (C++23) und WG14 N2645 (C++23) hinzugefügt, die die Präprozessordirektiven #elifdef und #elifndef eingeführt haben. Erfordert /std:clatest oder /std:c++latest.

Vorher:

#ifdef __cplusplus
  #include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif

Nachher:

#ifdef __cplusplus
  #include <atomic>
#elifndef __STDC_NO_ATOMICS__
  #include <stdatomic.h>
#else
  #include <custom_atomics_library.h>
#endif

Anwendung von _Alignas auf einen strukturierten Typ in C

Gilt für die Sprache C (C17 und höher). Außerdem zu Microsoft Visual Studio 17.9 hinzugefügt

Wenn in Versionen von Visual C++ vor Visual Studio 2022 Version 17.9 der Bezeichner _Alignas neben einem strukturierten Typ in einer Deklaration stand, wurde er nicht korrekt gemäß dem ISO-C-Standard angewendet.

// 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");

Gemäß dem ISO-C-Standard sollte dieser Code kompiliert werden, ohne dass static_assert eine Diagnose ausgibt.

Die Direktive _Alignas gilt nur für die Membervariable member1. Die Ausrichtung von struct Inner darf nicht geändert werden. Vor Visual Studio 17.9.1 wurde jedoch die Diagnose „falsche Ausrichtung“ ausgegeben. Der Compiler hat member2 an einem Offset von 32 Bytes innerhalb des Typs struct Outer ausgerichtet.

Da es sich hierbei um einen binäre Breaking Change handelt, wird nun eine Warnung ausgegeben, wenn diese Änderung in Kraft tritt. Warnung C5274 wird jetzt für das vorherige Beispiel auf Warnstufe 1 ausgegeben: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).

Außerdem wurde in früheren Versionen von Visual Studio der Bezeichner _Alignas ignoriert, wenn er neben einer anonymen Typdeklaration stand.

// 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");

Zuvor schlugen beide static_assert-Anweisungen beim Kompilieren dieses Codes fehl. Der Code lässt sich nun kompilieren, gibt aber die folgenden Ebene 1-Warnungen aus:

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)

Um das vorherige Verhalten zu erhalten, ersetzen Sie _Alignas(N) durch __declspec(align(N)). Im Gegensatz zu _Alignas gilt declspec(align) für den Typ.

Verbesserte Warnung C4706

Dabei handelt es sich um einen Breaking Change im Quellcode. Zuvor erkannte der Compiler nicht die Konvention, eine Zuweisung in Klammern einzuschließen, wenn eine Zuweisung beabsichtigt war, um die Warnung C4706 über Zuweisungen innerhalb eines bedingten Ausdrucks zu unterdrücken. Der Compiler erkennt jetzt die Klammern und unterdrückt die Warnung.

#pragma warning(error: 4706)

struct S
{
   auto mf()
   {
      if (value = 9)
         return value + 4;
      else
         return value;
   }

   int value = 9;
};

Der Compiler gibt die Warnung jetzt auch in Fällen aus, in denen die Funktion nicht referenziert wird. Da mf eine Inline-Funktion ist, die nicht referenziert wird, wurde die Warnung C4706 für diesen Code bisher nicht ausgegeben. Jetzt wird die Warnung ausgegeben:

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

Um diese Warnung zu beheben, verwenden Sie entweder einen Gleichheitsoperator, value == 9, wenn dies beabsichtigt war. Oder schließen Sie die Zuweisung in Klammern, (value = 9), ein, wenn eine Zuweisung beabsichtigt ist. Andernfalls, da die Funktion nicht referenziert ist, entfernen Sie sie.

Verbesserungen der Konformität in Visual Studio 2022, Version 17.9

Visual Studio 2022, Version 17.9 bietet die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Verhaltensänderungen im Microsoft C/C++ Compiler.

Eine umfassendere Zusammenfassung der Änderungen an der Standardvorlagenbibliothek finden Sie unter STL Änderungsprotokoll VS 2022 17.9.

Anwendung von _Alignas auf einen strukturierten Typ in C

In älteren Versionen von Visual C++ (vor Visual Studio 2022 Version 17.9) wurde _Alignas, wenn es neben einem Strukturtyp in einer Deklaration auftauchte, nicht korrekt gemäß dem ISO-C Standard angewendet. Zum Beispiel:

// 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");

Gemäß dem ISO-C-Standard sollte dieser Code kompiliert werden, ohne dass static_assert eine Diagnose ausgibt. Die Direktive _Alignas gilt nur für die Membervariable member1. Die Ausrichtung von struct Inner darf nicht geändert werden. Vor Version 17.9.1 von Visual Studio wurde jedoch die Diagnose „falsche Ausrichtung“ ausgegeben. Der Compiler hat member2 an einem 32-Byte-Offset innerhalb von struct Outer ausgerichtet.

Die Behebung dieses Problems ist eine binäre Änderung, so dass eine Warnung ausgegeben wird, wenn diese Änderung des Verhaltens angewendet wird. Für den vorhergehenden Code wird die Warnung C5274, „_Alignas gilt nicht mehr für den Typ 'Inner' (gilt nur für deklarierte Datenobjekte)“, jetzt auf Warnstufe 1 ausgegeben.

In früheren Versionen von Visual Studio wurde _Alignas ignoriert, wenn es neben einer anonymen Typdeklaration erschien. Zum Beispiel:

// 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");

Zuvor schlugen beide static_assert-Anweisungen beim Kompilieren dieses Codes fehl. Der Code wird jetzt kompiliert, aber mit den folgenden Warnungen der Ebene 1:

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)

Wenn Sie das frühere Verhalten wünschen, ersetzen Sie _Alignas(N) durch __declspec(align(N)). Im Gegensatz zu _Alignas kann declspec(align) auf einen Typ angewendet werden.

__VA_OPT__ ist als Erweiterung unter /Zc:preprocessor aktiviert.

Zu C++20 und C23 wurde __VA_OPT__ hinzugefügt. Vor dieser Ergänzung gab es keine Standardmethode, um ein Komma in einem variadischen Makro auszulassen. Um eine bessere Abwärtskompatibilität zu gewährleisten, ist __VA_OPT__ unter dem tokenbasierten Präprozessor /Zc:preprocessor in allen Sprachversionen aktiviert.

Zum Beispiel wird dies jetzt ohne Fehler kompiliert:

#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-Sprache

Für C23 sind die folgenden Optionen verfügbar, wenn Sie den Compilerschalter /std:clatest verwenden:

typeof
typeof_unqual

Die folgenden Versionen sind für alle C-Sprachversionen verfügbar:

__typeof__
__typeof_unqual__

C++-Standardbibliothek

C++23-Features

  • formattable, range_format, format_kind, und set_debug_format() als Teil des P2286R8-Formatierungsbereichs
  • <mdspan> pro P0009R18 und nachfolgenden Wortänderungen, die auf den C++23 Standard angewendet wurden.
  • format()-Zeiger pro P2510R3.

Verbesserungen der Konformität in Visual Studio 2022, Version 17.8

Visual Studio 2022, Version 17.8 bietet die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Verhaltensänderungen im Microsoft C/C++ Compiler.

/FU gibt einen Fehler aus

Der C-Compiler hat bisher die /FU-Option akzeptiert, obwohl er die verwaltete Kompilierung bereits seit einiger Zeit nicht unterstützt. Er gibt jetzt einen Fehler aus. Projekte, die diese Option übergeben, müssen sie nur auf C++/CLI-Projekte beschränken.

C++-Standardbibliothek

Die C++23 benannten Module std und std.compat sind jetzt beim Kompilieren mit /std:c++20 verfügbar.

Eine umfassendere Zusammenfassung der Änderungen an der C++-Standardbibliothek finden Sie unter STL Changelog VS 2022 17.8.

Verbesserungen der Konformität in Visual Studio 2022, Version 17.7

Visual Studio 2022, Version 17.7 bietet die folgenden hervorgehobenen Konformitätsverbesserungen, Fehlerbehebungen und Verhaltensänderungen im Microsoft C/C++ Compiler.

/std:clatest zum C-Compiler hinzugefügt

Dieser Switch verhält sich wie der /std:c++latest-Switch für den C++-Compiler. Die Option ermöglicht alle derzeit implementierten Compiler- und Standardbibliotheksfunktionen, die für den nächsten Entwurf C-Standard vorgeschlagen werden, sowie einige in Bearbeitung befindliche und experimentelle Funktionen.

C++-Standardbibliothek

Die <print>-Bibliothek wird jetzt unterstützt. Siehe P2093R14 Formatierte Ausgabe.

views::cartesian_product implementiert.

Eine umfassendere Zusammenfassung der Änderungen an der Standardvorlagenbibliothek finden Sie unter STL Changelog VS 2022 17.7.

using-Konformität

Zuvor konnte die using-Anweisung dazu führen, dass Namen aus verwendeten Namespaces sichtbar bleiben, wenn sie dies nicht sollten. Dies kann dazu führen, dass eine nicht qualifizierte Namenssuche einen Namen in einem Namespace findet, auch wenn keine using-Anweisung aktiv ist.

Hier sind einige Beispiele für das neue und alte Verhalten.
Verweise in den folgenden Kommentaren auf „(1)“ bedeuten den Aufruf von f<K>(t) im Namespace 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>()); 
    } 
} 

Dasselbe zugrunde liegende Problem kann dazu führen, dass Code, der zuvor kompiliert wurde, jetzt abgelehnt wird:

#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;
}

Verbesserte Konformität in Visual Studio 2022, Version 17.6

Visual Studio 2022, Version 17.6 bietet die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Verhaltensänderungen im Microsoft C/C++ Compiler.

volatile-Verbundzuweisungen nicht länger veraltet

In C++20 wurde die Anwendung bestimmter Operatoren auf Typen, die mit volatile qualifiziert waren, als veraltet eingestuft. Angenommen, der folgende Code wird mit cl /std:c++20 /Wall test.cpp kompiliert:

void f(volatile int& expr)
{
   ++expr;
}

In diesem Fall erzeugt der Compiler die folgende Warnung: test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20.

In C++20 wurden Verbundzuweisungsoperatoren (Operatoren der Form @=) als veraltet eingestuft. In C++23 werden die in C++20 ausgeschlossenen Verbundoperatoren nicht mehr als veraltet eingestuft. In C++23 führt der folgende Code beispielsweise nicht zu einer Warnung, während in C++20 eine Warnung ausgegeben wird:

void f(volatile int& e1, int e2)
{
   e1 += e2;
}

Weitere Informationen zu dieser Änderung finden Sie unter CWG:2654.

Umschreibung von Gleichheitsausdrücken kein Breaking Change (P2468R2)

In C++20 wurde der Compiler durch P2468R2 so geändert, dass er Code wie den folgenden akzeptiert:

struct S
{
    bool operator==(const S&);
    bool operator!=(const S&);
};
bool b = S{} != S{};

Der Compiler akzeptiert diesen Code, das heißt, dass der Compiler Code wie diesen strikter handhabt:

struct S
{
  operator bool() const;
  bool operator==(const S&);
};

bool b = S{} == S{};

Version 17.5 des Compilers akzeptiert dieses Programm. Version 17.6 des Compilers lehnt ihn ab. Um dies zu beheben, fügen Sie const zu operator== hinzu, um die Mehrdeutigkeit zu beseitigen. Oder fügen Sie der Definition einen entsprechenden operator!= hinzu, wie im folgenden Beispiel gezeigt:

struct S
{
  operator bool() const;
  bool operator==(const S&);
  bool operator!=(const S&);
};

bool b = S{} == S{};

Die Microsoft C/C++-Compilerversionen 17.5 und 17.6 akzeptieren das vorherige Programm und rufen S::operator== in beiden Versionen auf.

Das in P2468R2 beschriebene allgemeine Programmiermodell besagt, dass bei Vorhandensein eines entsprechenden operator!= für einen Typ das Umschreibungsverhalten üblicherweise unterdrückt wird. Die vorgeschlagene Korrektur für Code, der zuvor in C++17 kompiliert wurde, ist das Hinzufügen eines entsprechenden operator!=. Weitere Informationen finden Sie unter Programmierungsmodell.

Verbesserungen der Konformität in Visual Studio 2022 Version 17.4

Die Version 17.4 von Visual Studio 2022 enthält die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Behavior Changes im Microsoft C++-Compiler.

Zugrunde liegende Typen von enum ohne eigenen Gültigkeitsbereich und ohne festen Typ

In Visual Studio-Versionen vor Visual Studio 2022 Version 17.4 hat der C++-Compiler den zugrunde liegenden Typ einer Enumeration ohne eigenen Gültigkeitsbereich und ohne festen Basistyp nicht ordnungsgemäß ermittelt. Unter /Zc:enumTypes wird das Standardverhalten nun ordnungsgemäß implementiert.

Der C++-Standard erfordert, dass der zugrunde liegende Typ von enum groß genug ist, um alle Enumeratoren in dieser enumaufnehmen zu können. Ausreichend große Enumeratoren können den zugrunde liegenden Typ von enum auf unsigned int, long long oder unsigned long long festlegen. Bisher hatten solche enum-Typen im Microsoft-Compiler immer den zugrunde liegenden Typ int, unabhängig von den Enumeratorwerten.

Wenn die Option /Zc:enumTypes aktiviert wird, stellt sie eine potenzielle Quelle für Breaking Changes in Binärdateien dar. Sie ist standardmäßig deaktiviert und wird von /permissive- nicht aktiviert, da sich die Korrektur auf die Binärkompatibilität auswirken könnte. Einige Enumerationstypen ändern die Größe, wenn die entsprechende Korrektur aktiviert ist. Bestimmte Windows SDK-Header enthalten solche Enumerationsdefinitionen.

Beispiel

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
};

Typen von Enumeratoren innerhalb einer enum-Definition ohne festen zugrunde liegenden Typ

In Visual Studio-Versionen vor Visual Studio 2022 Version 17.4 hat der C++-Compiler die Typen von Enumeratoren nicht ordnungsgemäß modelliert. Es konnte vorkommen, dass in Enumerationen ohne einen festen zugrunde liegenden Typ vor der schließende Klammer der Enumeration ein falscher Typ angenommen wurde. Unter /Zc:enumTypes implementiert der Compiler das Standardverhalten nun ordnungsgemäß.

Der C++-Standard legt fest, dass innerhalb einer Enumerationsdefinition, der kein fester Typ zugrunde liegt, die Typen der Enumeratoren durch Initialisierer bestimmt werden. Für Enumeratoren ohne Initialisierer kann der Typ des vorherigen Enumerators (unter Berücksichtigung eines Überlaufs) angenommen werden. Bisher erhielten solche Enumeratoren immer den abgeleiteten Typ der Enumeration mit einem Platzhalter für den zugrunde liegenden Typ (in der Regel int).

Wenn die Option /Zc:enumTypes aktiviert wird, stellt sie eine potenzielle Quelle für Breaking Changes in Binärdateien dar. Sie ist standardmäßig deaktiviert und wird von /permissive- nicht aktiviert, da sich die Korrektur auf die Binärkompatibilität auswirken könnte. Einige Enumerationstypen ändern die Größe, wenn die entsprechende Korrektur aktiviert ist. Bestimmte Windows SDK-Header enthalten solche Enumerationsdefinitionen.

Beispiel

enum Enum {
    A = 'A',
    B = sizeof(A)
};

static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes

In diesem Beispiel sollte der Enumerator A vor der schließenden Klammer der Aufzählung den Typ char haben, also sollte B mit sizeof(char) initialisiert werden. Vor der Korrektur von /Zc:enumTypes hatte A den Enumerationstyp Enum mit dem abgeleiteten zugrunde liegenden Typ int und B wurde mit sizeof(Enum) oder 4 initialisiert.

Konformitätsverbesserungen in Visual Studio 2022, Version 17.3

Die Version 17.3 von Visual Studio 2022 enthält die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Behavior Changes im Microsoft C/ C++-Compiler.

C: Verbesserte Modifiziererkompatibilitätsprüfung zwischen Zeigern

Modifizierer zwischen Zeigern wurden vom C-Compiler nicht ordnungsgemäß verglichen. Das gilt insbesondere für void*. Dieser Fehler konnte dazu führen, dass fälschlicherweise eine Inkompatibilität zwischen const int** und void* sowie eine Kompatibilität zwischen int* volatile* und void* diagnostiziert wurde.

Beispiel

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
}

Verbesserungen der Konformität in Visual Studio 2022, Version 17.2

Die Version 17.2 von Visual Studio 2022 enthält die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Behavior Changes im Microsoft C++-Compiler.

Unterminierte bidirektionale Zeichenwarnungen

Visual Studio 2022 Version 17.2 fügt Ebene 3 Warnung C5255 für unterminierte Unicode bidirektionale Zeichen in Kommentaren und Zeichenfolgen hinzu. Die Warnung behandelt ein Sicherheitsproblem, das in Trojanische Quelle: Unsichtbare Sicherheitsrisiken von Nicholas Boucher und Ross Anderson beschrieben wird. Weitere Informationen zu Unicode bidirektionalen Zeichen finden Sie unter Unicode® Standard Anhang #9: UNICODE BIDIRECTIONAL ALGORITHM.

Warnung C5255 adressiert nur Dateien, die nach der Konvertierung Unicode bidirektionale Zeichen enthalten. Diese Warnung gilt für UTF-8-, UTF-16- und UTF-32-Dateien, sodass die richtige Quellcodierung bereitgestellt werden muss. Diese Änderung ist ein Breaking Change der Quelle.

Beispiel (vor/nach)

In Versionen von Visual Studio vor Visual Studio 2022 Version 17.2 hat ein unterminiertes bidirektionales Zeichen keine Warnung erzeugt. In Visual Studio 2022 Version 17.2 wird die Warnung C5255 generiert:

// 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 Version 17.2 behebt einen Fehler in <charconv>from_chars()float Tiebreaker-Regeln, die falsche Ergebnisse erzeugt haben. Dieser Fehler hat dezimale Zeichenfolgen betroffen, die sich an der genauen Mitte der aufeinander folgenden float Werte befinden, innerhalb eines schmalen Bereichs. (Die kleinsten und größten betroffenen Werte waren 32768.009765625 bzw 131071.98828125. Die Tiebreaker-Regel wollte auf "gerade" runden, und "gerade" ist "down", aber die Implementierung fälschlicherweise aufgerundet (double war nicht betroffen.) Weitere Informationen und Implementierungsdetails finden Sie unter microsoft/STL#2366.

Diese Änderung wirkt sich auf das Laufzeitverhalten im angegebenen Bereich von Fällen aus:

Beispiel

// 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");
}

Versionen vor Version 17.2 von Visual Studio 2022:

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, Version 17.2 und höher:

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__ stellt __STDC__ für C zur Verfügung

Der C-Standard erfordert, dass eine konforme C-Implementierung __STDC__ als 1 definiert. Aufgrund des Verhaltens der UCRT, die POSIX-Funktionen nicht verfügbar macht, wenn __STDC__1 ist, ist es nicht möglich, dieses Makro für C standardmäßig zu definieren, ohne Änderungen an den stabilen Sprachversionen einzuführen. In Visual Studio 2022 Version 17.2 und höher fügen Sie die Konformitätsoption /Zc:__STDC__ hinzu, die dieses Makro definiert. Es gibt keine negative Version der Option. Derzeit planen wir, diese Option standardmäßig für zukünftige Versionen von C zu verwenden.

Diese Änderung ist ein Breaking Change der Quelle. Dies gilt, wenn der C11- oder C17-Modus aktiviert ist (/std:c11 oder /std:c17) und /Zc:__STDC__ angegeben ist.

Beispiel

// 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__

*/

Warnung für fehlende Klammern

Warnung C5246 meldet fehlende Klammern während der aggregierten Initialisierung eines Unterobjekts. Vor Visual Studio 2022 Version 17.2 behandelte die Warnung nicht den Fall eines Anonymen struct oder union.

Diese Änderung ist ein Breaking Change der Quelle. Es gilt, wenn die standardmäßige Warnung C5246 aktiviert ist.

Beispiel

In Visual Studio 2022 Version 17.2 und höher verursacht dieser Code jetzt einen Fehler:

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
*/

Um dieses Problem zu beheben, fügen Sie dem Initializer Klammern hinzu:

void f()
{
   S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}

Verbesserungen der Konformität in Visual Studio 2022, Version 17.1

Die Version 17.1 von Visual Studio 2022 enthält die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Behavior Changes im Microsoft C++-Compiler.

Erkennung einer falsch formatierten Standarderfassung in nicht lokalen Lambdaausdrücken

Der C++-Standard lässt nur zu, dass ein Lambdaausdruck im Blockbereich einen Erfassungsstandard hat. In Visual Studio 2022, Version 17.1 und höher erkennt der Compiler, wenn eine Standarderfassung in einem nicht lokalen Lambdaausdruck unzulässig ist. Es sendet eine neue Warnung auf Ebene 4, C5253.

Diese Änderung ist ein Breaking Change der Quelle. Sie gilt in jedem Modus, der den neuen Lambdaprozessor verwendet: /Zc:lambda, /std:c++20 oder /std:c++latest.

Beispiel

In Visual Studio 2022 Version 17.1 gibt dieser Code nun einen Fehler aus:

#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; };
//              ^

Um dieses Problem zu beheben, entfernen Sie den Erfassungsstandard:

#pragma warning(error:5253)

auto incr = [](int value) { return value + 1; };

C4028 ist jetzt C4133 für Funktion-zu-Zeiger-Vorgänge

Vor Visual Studio 2022 Version 17.1 hat der Compiler bei bestimmten Zeiger-zu-Funktion-Vergleichen im C-Code eine falsche Fehlermeldung ausgegeben. Die falsche Meldung wurde ausgegeben, wenn Sie zwei Funktionszeiger mit gleicher Argumentanzahl, aber inkompatiblen Typen verglichen. Jetzt wird eine andere Warnung ausgegeben, die die Zeiger-zu-Funktion-Inkompatibilität und nicht die Nichtübereinstimmung von Funktionsparametern meldet.

Diese Änderung ist ein Breaking Change der Quelle. Sie gilt, wenn Code in C kompiliert wird.

Beispiel

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)'

Fehler bei nicht abhängigem static_assert-Ausdruck

In Visual Studio 2022 Version 17.1 und später, wenn der Ausdruck, der mit einem static_assert verbunden ist, kein abhängiger Ausdruck ist, wertet der Compiler den Ausdruck aus, wenn er geparst wird. Wenn der Ausdruck als false ausgewertet wird, gibt der Compiler eine Fehlermeldung aus. Vorher führte der Compiler diese Analyse nicht durch, wenn sich der static_assert innerhalb des Textkörpers einer Funktionsvorlage (oder innerhalb des Textkörpers einer Memberfunktion einer Klassenvorlage) befand.

Diese Änderung ist ein Breaking Change der Quelle. Sie gilt in jedem Modus, der /permissive- oder /Zc:static_assert beinhaltet. Dieser Behavior Change kann mithilfe der Compileroption /Zc:static_assert- deaktiviert werden.

Beispiel

In Visual Studio 2022 Version 17.1 und höher verursacht dieser Code jetzt einen Fehler:

template<typename T>
void f()
{
   static_assert(false, "BOOM!");
}

Um dieses Problem zu beheben, machen Sie den Ausdruck abhängig. Beispiel:

template<typename>
constexpr bool dependent_false = false;

template<typename T>
void f()
{
   static_assert(dependent_false<T>, "BOOM!");
}

Mit dieser Änderung gibt der Compiler nur dann eine Fehlermeldung aus, wenn die Funktionsvorlage f instanziiert wird.

Verbesserungen der Konformität in Visual Studio 2022 17.0

Die Version 17.0 von Visual Studio 2022 enthält die folgenden Konformitätsverbesserungen, Fehlerbehebungen und Behavior Changes im Microsoft C/C++-Compiler.

Warnung zur Bitfeldbreite für den Enumerationstyp

Wenn Sie eine Instanz eines Enumerationstyps als Bitfeld deklarieren, muss die Breite des Bitfelds alle möglichen Werte der Enumeration aufnehmen. Andernfalls gibt der Compiler eine Diagnosemeldung aus. Betrachten Sie das folgende Beispiel:

enum class E : unsigned { Zero, One, Two };

struct S {
  E e : 1;
};

Ein*e Programmierer*in erwartet möglicherweise, dass ein S::e-Klassenmember alle der explizit benannten enum-Werte enthalten kann. Aufgrund der Anzahl der Enumerationselemente ist dies nicht möglich. Das Bitfeld kann den Bereich der explizit bereitgestellten Werte von E (konzeptuell die Domäne von E) nicht abdecken. Um das Problem zu lösen, dass die Bitfeldbreite für die Domäne der Enumeration nicht groß genug ist, wird eine neue (standardmäßig deaktivierte) Warnung zu MSVC hinzugefügt:

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 };
                                     ^

Dieses Compilerverhalten ist ein quellbezogener und binärer Breaking Change, der sich auf alle /std - und /permissive -Modi auswirkt.

Fehler beim geordneten Zeigervergleich mit nullptr oder 0

Der C++-Standard hat versehentlich einen geordneten Zeigervergleich mit nullptr oder 0 zugelassen. Beispiel:

bool f(int *p)
{
   return p >= 0;
}

Im WG21-Papier N3478 wurde dieser Fehler entfernt. Diese Änderung wird in MSVC implementiert. Wenn das Beispiel mithilfe von /permissive- (und /diagnostics:caret ) kompilieren wird, wird der folgende Fehler ausgegeben:

t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
    return p >= 0;
             ^

Dieses Compilerverhalten ist ein quellbezogener und binärer Breaking Change, der sich auf Code auswirkt, der mithilfe von /permissive- in allen /std -Modi kompiliert wurde.

Siehe auch

Microsoft C/C++-Sprachkonformität