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.
Drucken leerer Zeilen mit println
Pro P3142R0 ist es jetzt einfach, eine leere Zeile mit println
. Dieses Feature ist beim Kompilieren mit /std:c++latest
verfügbar.
Vor dieser Änderung haben Sie geschrieben: Jetzt schreiben Sie: println("");
println();
.
println();
entsprichtprintln(stdout);
println(FILE* stream);
entsprichtprintln(stream, "\n");
Umgesetzt range_formatter
Pro P2286R8range_formatter
wird jetzt implementiert. Dieses Feature ist beim Kompilieren mit /std:c++latest
verfü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:
Die folgenden Versionen sind für alle C-Sprachversionen verfügbar:
C++-Standardbibliothek
C++23-Features
formattable
,range_format
,format_kind
, undset_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 enum
aufnehmen 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.