Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Microsoft C/C++ ve Visual Studiu (MSVC) vylepšuje shodu a opravuje chyby v každé verzi. Tento článek uvádí významná vylepšení v hlavní verzi a potom podle verze. Pokud chcete přejít přímo na změny konkrétní verze, použijte odkazy v tomto článku v horní části tohoto článku.
Tento dokument uvádí změny ve Visual Studio 2022.
Změny v dřívějších verzích sady Visual Studio:
Verze | Vylepšení shody - odkaz |
---|---|
2019 | Vylepšení shody jazyka C++ v sadě Visual Studio 2019 |
2017 | Vylepšení souladu C++ ve Visual Studio 2017 |
2003-2015 | Novinky Visual C++ 2003–2015 |
Vylepšení souladu v aplikaci Visual Studio 2022 verze 17.14
Visual Studio 2022 verze 17.14 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Vylepšení shody
- Posílení zabezpečení standardní knihovny (P3471R4) změní některé instance nedefinovaného chování ve standardní knihovně na volání __fastfail. Ve výchozím nastavení je vypnuto. Definujte
_MSVC_STL_HARDENING=1
pro celý projekt, aby se povolil.
Vylepšené chování
- Implementovali jsme "destruktorové náhrobky" pro zmírnění chyb použití bez použití. Ve výchozím nastavení je vypnuto. Definujte
_MSVC_STL_DESTRUCTOR_TOMBSTONES=1
pro celý projekt, aby se povolil.
Opravy chyb
Opravili jsme chyby kompilátoru errantu při použití
<format>
v projektu CUDA.Opravili jsme problém kompilátoru, který způsoboval, že adresa místní proměnné mohla během
constexpr
vyhodnocení uniknout. Příklad: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
Příklad č. 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 }
Kód zkompilovaný s
/permissive-
již nepřijímá kombinacifriend
astatic
v deklaraci. Oprava je obvykle odstraněnístatic
z deklarace. Příklad:struct S { friend static void f(); // Previously accepted, now emits error C2440: 'static' cannot be used with 'friend' };
Vazba odkazů na typy kvalifikované nestálostí byla opravena při odkazování na základní nebo odvozenou třídu. Příklad:
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.
Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.14.
Vylepšení kompatibility v sadě Visual Studio 2022 verze 17.13
Visual Studio 2022 verze 17.13 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu protokol změn STL VS 2022 17.13.
Vyhledávání závislé na argumentech (ADL)
Jazykové konstrukce, jako je "range-for" a strukturované vazby, mají speciální pravidla pro vyhledávání závislá na argumentech pro určité identifikátory, jako jsou begin
, end
nebo get
. Dříve toto vyhledávání zahrnovalo kandidáty z std
oboru názvů, i když obor názvů std
není součástí běžné sady přidružených oborů názvů pro vyhledávání závislé na argumentech.
Programy, které zavedly deklarace pro std
pro tyto konstrukty již nejsou kompilovány. Místo toho by deklarace měly být v normálním přidruženém oboru názvů pro příslušné typy (pravděpodobně včetně globálního oboru názvů).
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>'
{
...
}
}
Nelze upravit makra vyhrazená pro implementaci
Dříve kompilátor umožňoval změnu nebo zrušení definice některých maker poskytovaných implementací, jako je _MSC_EXTENSIONS
. Změna definice určitých maker může mít za následek nedefinované chování.
Při pokusu o změnu nebo zrušení definice některých rezervovaných makro názvů se nyní zobrazí upozornění úrovně 1 C5308
. V režimu /permissive-
se toto upozornění považuje za chybu.
#undef _MSC_EXTENSIONS // Warning C5308: Modifying reserved macro name `_MSC_EXTENSIONS` may cause undefined behavior
Vylepšení souladu v aplikaci Visual Studio 2022 verze 17.12
Visual Studio 2022 verze 17.12 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.12.
_com_ptr_t::operator bool()
je teď explicitní
Jedná se o zdrojovou nebo binární změnu způsobující nekompatibilitu.
Implicitní převod do bool
z _com_ptr_t
instancí může být překvapivý nebo může vést k chybám kompilátoru.
C.164: Vyhněte se implicitním převodním operátorům v pokynech pro C++ Core Guidelines, které nedoporučují implicitní převodní funkce. A _com_ptr_t
obsahoval implicitní převody na oba bool
a Interface*
. Tyto dva implicitní převody můžou vést k nejednoznačnostem.
Převod na bool
je nyní explicitní. Převod na Interface*
se nezmění.
K dispozici je makro pro odhlášení od tohoto nového chování a obnovení předchozího implicitního převodu. Skompilujte s /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL
pro zrušení této změny. Doporučujeme upravit kód tak, aby nespoléhal na implicitní převody.
Příklad:
#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'
}
Výrazy konstant už nejsou vždy noexcept
v povoleném režimu.
Jedná se o zdrojovou nebo binární změnu způsobující nekompatibilitu.
Konstantní výraz byl vždy noexcept
, i když zahrnoval volání funkce deklarované s potenciálně vyvolanou specifikací výjimky. Toto znění bylo odebráno v jazyce C++17, ačkoli kompilátor Microsoft Visual C++ ho stále podporuje v /permissive
režimu ve všech jazykových verzích jazyka C++.
Chování režimu /permissive
bylo odebráno. Konstantní výrazy už nemají zvláštní implicitní chování.
Specifikátor noexcept
constexpr
funkcí je nyní respektován ve všech režimech. Tato změna se vyžaduje pro správnou implementaci pozdějších základních řešení problémů, která závisí na standardním noexcept
chování.
Příklad:
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.
}
Zlepšení shody v sadě Visual Studio 2022 verze 17.11
Visual Studio 2022 verze 17.11 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.11.
Tisk prázdných řádků pomocí println
Na P3142R0 je teď snadné vygenerovat prázdný řádek s println
. Tato funkce je k dispozici při kompilaci pomocí /std:c++latest
.
Před touto změnou jste napsali: println("");
Nyní píšete: println();
.
-
println();
je ekvivalentníprintln(stdout);
-
println(FILE* stream);
je ekvivalentníprintln(stream, "\n");
Implementováno range_formatter
Podle P2286R8 je nyní implementováno. Tato funkce je k dispozici při kompilaci pomocí /std:c++latest
.
Vylepšení shody v Visual Studio 2022 verze 17.10
Visual Studio 2022 verze 17.10 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Podrobný přehled změn provedených ve standardní knihovně šablon, včetně změn shody, oprav chyb a vylepšení výkonu, najdete v tématu STL Changelog VS 2022 17.10.
Specializace operátoru převodu s explicitně zadaným návratovým typem
Kompilátor někdy nesprávně specializoval převodní operátory, což mohlo vést k neshodě návratového typu. K těmto neplatným specializacem už nedojde. Jedná se o změnu způsobující chybu zdrojového kódu.
// 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
}
Přidání podpory pro #elifdef
a #elifndef
Byla přidána podpora pro WG21 P2334R1 (C++23) a WG14 N2645 (C++23), která zavedla direktivy preprocesoru #elifdef
a #elifndef
preprocesoru.
Vyžaduje /std:clatest
nebo /std:c++latest
.
Před:
#ifdef __cplusplus
#include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Po:
#ifdef __cplusplus
#include <atomic>
#elifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Použití strukturovaného _Alignas
typu v jazyce C
Platí pro jazyk C (C17 a novější). Přidáno také do sady Microsoft Visual Studio 17.9
Ve verzích Visual C++ před Visual Studio 2022 verzí 17.9, pokud se specifikátor _Alignas
objevil vedle strukturovaného typu v deklaraci, nebyl správně použit podle standardu ISO-C.
// compile with /std:c17
#include <stddef.h>
struct Outer
{
_Alignas(32) struct Inner { int i; } member1;
struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");
Podle standardu ISO-C by se měl tento kód zkompilovat bez vyvolání diagnostiky.
Direktiva _Alignas
se vztahuje pouze na členské proměnné member1
. Nesmí měnit zarovnání struct Inner
. Před verzí Visual Studio 17.9.1 však byla vygenerována diagnostika nesprávného zarovnání. Kompilátor zarovnal member2
na posun o 32 bajtů v typu struct Outer
.
Jedná se o binární zásadní změnu, takže se teď vygeneruje upozornění, když se tato změna projeví. Upozornění C5274 je nyní generováno na úrovni upozornění 1 pro předchozí příklad: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects)
.
V předchozích verzích sady Visual Studio byl také ignorován specifikátor, který se objevil vedle deklarace anonymního typu.
// 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");
Dříve se oba static_assert
příkazy při kompilaci tohoto kódu nezdařily. Kód se teď zkompiluje, ale vygeneruje následující upozornění na úroveň 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)
Chcete-li získat předchozí chování, nahraďte _Alignas(N)
.__declspec(align(N))
Na rozdíl od _Alignas
se declspec(align)
vztahuje na typ.
Vylepšené upozornění C4706
Jedná se o změnu způsobující chybu zdrojového kódu. Dříve kompilátor nedetekoval konvenci obalení přiřazení do závorek, pokud bylo přiřazení zamýšleno, aby potlačil upozornění C4706 týkající se přiřazení v rámci podmíněného výrazu. Kompilátor teď rozpozná závorky a potlačí upozornění.
#pragma warning(error: 4706)
struct S
{
auto mf()
{
if (value = 9)
return value + 4;
else
return value;
}
int value = 9;
};
Kompilátor teď také vygeneruje upozornění v případech, kdy se na funkci neodkazuje. Dříve, protože mf
je vložená funkce, na kterou se neodkazuje, upozornění C4706 se pro tento kód nevygenerovalo. Nyní se vygeneruje upozornění:
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
Chcete-li toto upozornění opravit, pokud to bylo zamýšleno, použijte operátor rovnosti value == 9
. Nebo zabalte přiřazení do závorek, (value = 9)
pokud má přiřazení být provedeno. Jelikož funkce není odkazovaná, odeberte ji.
Vylepšení shody ve Visual Studio 2022 verze 17.9
Visual Studio 2022 verze 17.9 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Širší souhrn změn provedených v knihovně standardní šablony najdete v tématu STL Changelog VS 2022 17.9.
Použití strukturovaného _Alignas
typu v jazyce C
Ve verzích Visual C++ před sadou Visual Studio 2022 verze 17.9, když se _Alignas
objevilo vedle typu struktury v deklaraci, nebylo správně aplikováno podle standardu ISO-C. Příklad:
// 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");
Podle standardu ISO-C by se měl tento kód zkompilovat, aniž by generoval diagnostiku pomocí static_assert
. Direktiva _Alignas
se vztahuje pouze na členské proměnné member1
. Nesmí měnit zarovnání struct Inner
. Před verzí 17.9.1 sady Visual Studio se však generovala chybová hláška „incorrect alignment“. Kompilátor zarovnal member2
na offset 32 bajtů uvnitř struct Outer
.
Oprava této chyby je binární zásadní změnou, takže při použití této změny chování je vydáno varování. U předchozího kódu se varování C5274, "_Alignas
již neplatí pro typ 'Inner' (platí pouze pro deklarované datové objekty)", nyní generuje na úrovni varování 1.
V předchozích verzích sady Visual Studio byla ignorována, _Alignas
když se zobrazila vedle deklarace anonymního typu. Příklad:
// 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");
Dříve se oba static_assert
příkazy při kompilaci tohoto kódu nezdařily. Kód se teď zkompiluje, ale s následujícími upozorněními úrovně 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)
Pokud chcete dřívější chování, nahraďte ho _Alignas(N)
.__declspec(align(N))
Na rozdíl od _Alignas
lze declspec(align)
aplikovat na typ.
__VA_OPT__
je povolen jako rozšíření v části /Zc:preprocessor
__VA_OPT__
byl přidán do C++20 a C23. Před jeho přidáním neexistoval standardní způsob, jak vynechat čárku ve variadickém makru. Aby byla zajištěna lepší zpětná kompatibilita, __VA_OPT__
je povolena pod preprocesorem /Zc:preprocessor
založeným na tokenech ve všech jazykových verzích.
Teď se například zkompiluje bez chyby:
#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")
Jazyk C23
Pro C23 jsou při použití přepínače kompilátoru /std:clatest
k dispozici následující možnosti:
Pro všechny jazykové verze jazyka C jsou k dispozici následující:
Standardní knihovna C++
Funkce C++23
-
formattable
,range_format
,format_kind
, aset_debug_format()
v rámci formátovacích rozsahů P2286R8 -
<mdspan>
podle P0009R18 a následných změn formulace, které byly použity na standard C++23. -
format()
ukazatele podle P2510R3.
Vylepšení shody v Visual Studio 2022 verze 17.8
Visual Studio 2022 verze 17.8 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
/FU
vyvolá chybu
Kompilátor jazyka /FU
C tuto možnost přijal, i když nějakou dobu nepodporuje spravovanou kompilaci. Teď se zobrazí chyba. Projekty, které splňují tuto možnost, musí ji omezit na projekty C++/CLI.
Standardní knihovna C++
Pojmenované moduly std
C++23 a std.compat
jsou nyní k dispozici při kompilaci pomocí /std:c++20
.
Širší souhrn změn provedených ve standardní knihovně C++ najdete v tématu STL Changelog VS 2022 17.8.
Vylepšení souladu v Visual Studio 2022 verze 17.7
Visual Studio 2022 verze 17.7 obsahuje následující zvýrazněná vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Přidáno /std:clatest
do kompilátoru jazyka C
Tento přepínač se chová jako /std:c++latest
přepínač kompilátoru jazyka C++. Přepínač umožňuje všechny aktuálně implementované funkce kompilátoru a standardní knihovny navržené pro další verzi standardu jazyka C a také některé probíhající a experimentální funkce.
Standardní knihovna C++
Knihovna <print>
je nyní podporovaná. Viz P2093R14 formátovaný výstup.
Implementováno views::cartesian_product
.
Širší souhrn změn provedených v knihovně standardních šablon najdete v tématu STL Changelog VS 2022 17.7.
using
konformita
Dříve mohla direktiva using
způsobit, že názvy z použitých oborů názvů zůstávaly viditelné i tehdy, kdy by neměly. Může to způsobit, že vyhledávání nekvalifikovaných názvů najde název v oboru názvů, i když není žádná směrnice using
aktivní.
Tady je několik příkladů nového a starého chování.
Odkazy v následujících komentářích na "(1)" znamenají volání funkce f<K>(t)
v jmenném prostoru 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>());
}
}
Stejný základní problém může způsobit odmítnutí kódu, který byl dříve zkompilován:
#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;
}
Vylepšení kompatibility pro Visual Studio 2022 verzi 17.6
Visual Studio 2022 verze 17.6 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Složená volatile
přiřazení už nejsou zastaralá
C++20 označilo použití určitých operátorů pro typy kvalifikované pomocí volatile
za zastaralé. Například při kompilaci následujícího kódu s cl /std:c++20 /Wall test.cpp
:
void f(volatile int& expr)
{
++expr;
}
Kompilátor vytvoří test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20
.
V jazyce C++20 byly operátory složeného přiřazení (operátory formuláře @=
) zastaralé. V jazyce C++23 už nejsou složené operátory označené jako zastaralé v C++20 považované za zastaralé. Například v jazyce C++23 následující kód negeneruje upozornění, zatímco v jazyce C++20:
void f(volatile int& e1, int e2)
{
e1 += e2;
}
Další informace o této změně naleznete v tématu CWG:2654
Přepisování rovnosti ve výrazech je méně zásadní změnou (P2468R2)
V C++20 P2468R2 změnil kompilátor tak, aby přijímal kód, například:
struct S
{
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} != S{};
Kompilátor přijímá tento kód, což znamená, že kompilátor je přísnější s kódem, například:
struct S
{
operator bool() const;
bool operator==(const S&);
};
bool b = S{} == S{};
Tento program přijímá verze 17.5 kompilátoru. Verze 17.6 kompilátoru ji odmítne. Chcete-li to opravit, přidejte const
do operator==
a odstraňte tak nejednoznačnost. Nebo přidejte odpovídající operator!=
k definici, jak je znázorněno v následujícím příkladu.
struct S
{
operator bool() const;
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} == S{};
Kompilátory Microsoft C/C++ ve verzích 17.5 a 17.6 přijímají předchozí program a provedou volání na S::operator==
v obou verzích.
Obecný programovací model popsaný v P2468R2 spočívá v tom, že pokud existuje odpovídající operator!=
pro typ, obvykle potlačí přepisovací chování. Přidání odpovídajícího operator!=
je navrhovanou opravou pro kód, který byl dříve kompatibilní s C++17. Další informace naleznete v tématu Programovací model.
Vylepšení souladu v sadě Visual Studio 2022 verze 17.4
Visual Studio 2022 verze 17.4 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Základní typy nesvázané bez pevného typu enum
Ve verzích sady Visual Studio před sadou Visual Studio 2022 verze 17.4 kompilátor jazyka C++ neurčil správně základní typ neskopovaného výčtu bez pevného základního typu. V části /Zc:enumTypes
, nyní správně implementujeme standardní chování.
Standard jazyka C++ vyžaduje, aby byl základní typ dostatečně enum
velký, aby pojmul všechny enumerátory v daném enum
. Dostatečně velcí enumerátory mohou nastavit základní typ enum
na unsigned int
, long long
nebo unsigned long long
. Dříve tyto enum
typy měly vždy základní typ int
v kompilátoru Microsoftu bez ohledu na hodnoty enumerátoru.
Pokud je možnost /Zc:enumTypes
povolena, může dojít k potenciální změně, která poruší funkčnost, jak na úrovni zdrojového kódu, tak i binární úrovni. Ve výchozím nastavení je vypnutý, a není povolený pomocí /permissive-
, protože oprava může ovlivnit binární kompatibilitu. Některé typy výčtů mění velikost, když je povolena odpovídající oprava. Některé hlavičky sady Windows SDK zahrnují takové definice výčtu.
Příklad
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
};
Typy výčtů v definici enum
bez pevného podkladového typu
Ve verzích sady Visual Studio před sadou Visual Studio 2022 verze 17.4 kompilátor jazyka C++ nemodeloval správně typy výčtů. Před ukončovací závorkou výčtu by se mohl předpokládat nesprávný typ v rámci výčtů bez pevného základního typu. V části /Zc:enumTypes
, kompilátor nyní správně implementuje standardní chování.
Standard jazyka C++ určuje, že v rámci definice výčtu bez pevně stanoveného základního typu inicializátory určují typy výčtových konstant. Nebo pro enumerátory bez inicializátoru podle typu předchozího enumerátoru (účetující přetečení). Dříve byly těmto enumerátorům vždy přiřazovány odvozené typy výčtu se zástupným symbolem pro základní datový typ (obvykle int
).
Pokud je možnost /Zc:enumTypes
povolena, může dojít k potenciální změně, která poruší funkčnost, jak na úrovni zdrojového kódu, tak i binární úrovni. Ve výchozím nastavení je vypnutý, a není povolený pomocí /permissive-
, protože oprava může ovlivnit binární kompatibilitu. Některé typy výčtů mění velikost, když je povolena odpovídající oprava. Některé hlavičky sady Windows SDK zahrnují takové definice výčtu.
Příklad
enum Enum {
A = 'A',
B = sizeof(A)
};
static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes
V tomto příkladu by enumerátor A
měl mít typ char
před závorkou výčtu, takže B
by měl být inicializován pomocí sizeof(char)
. Před opravou měl /Zc:enumTypes
A
typ Enum
výčtu s odvozeným základním typem int
, a B
byl inicializován pomocí sizeof(Enum)
nebo 4.
Vylepšení souladu v sadě Visual Studio 2022 verze 17.3
Visual Studio 2022 verze 17.3 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
C: Vylepšená kontrola kompatibility modifikátorů mezi ukazateli
Kompilátor jazyka C správně nerovnal modifikátory mezi ukazateli, zejména void*
. Tato chyba by mohla vést k nesprávné diagnostice nekompatibility mezi const int**
a void*
a kompatibility mezi int* volatile*
a void*
.
Příklad
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
}
Vylepšení kompatibility v sadě Visual Studio 2022 verze 17.2
Visual Studio 2022 verze 17.2 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Upozornění na neukončené obousměrné znaky
Visual Studio 2022 verze 17.2 přidává upozornění na úroveň 3 C5255 pro neukončené znaky Unicode obousměrné v komentářích a řetězcích. Toto upozornění se zabývá bezpečnostním problémem popsaným v Trojan Source: Neviditelné zranitelnosti Nicholasem Boucherem a Rossem Andersonem. Další informace o obousměrnýchch kódech Unicode naleznete v článku Standardní příloha unicode® č. 9: UNICODE BIDIRECTIONAL ALGORITHM.
Upozornění C5255 řeší pouze soubory, které po převodu obsahují obousměrné znaky Unicode. Toto upozornění platí pro soubory UTF-8, UTF-16 a UTF-32, takže musí být zadáno správné kódování zdroje. Tato změna narušuje kompatibilitu se zdrojem.
Příklad (před/po)
Ve verzích Visual Studio před Visual Studio 2022 verze 17.2 neuzavřený obousměrný znak nevyvolal varování. Visual Studio 2022 verze 17.2 generuje upozornění 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
rozhodující bod
Visual Studio 2022 verze 17.2 opravuje chybu v <charconv>
from_chars()
float
pravidlech tiebreakeru, která vytvořila nesprávné výsledky. Tato chyba ovlivnila desetinné řetězce, které byly na přesné střední bodě po sobě jdoucích float
hodnot v úzkém rozsahu. cs-CZ: (Nejmenší a největší ovlivněné hodnoty byly 32768.009765625
a 131071.98828125
.) Pravidlo pro rozlišení při rovnosti chtělo zaokrouhlit na "sudé", a "sudé" v tomto případě znamenalo "dolů", ale implementace nesprávně zaokrouhlila "nahoru" (hodnota double
zůstala neovlivněná). Další informace a podrobnosti o implementaci najdete na microsoft/STL#2366.
Tato změna má vliv na chování modulu runtime v zadaném rozsahu případů:
Příklad
// 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");
}
Ve verzích před Visual Studio 2022 verze 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.
Ve Visual Studiu 2022 verze 17.2 a novější:
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__
zpřístupní __STDC__
pro jazyk C
Standard jazyka C vyžaduje, aby odpovídající implementace jazyka C byla definována __STDC__
jako 1
. Vzhledem k chování UCRT, který nezpřístupňuje funkce POSIX, pokud __STDC__
je 1
, není možné definovat toto makro pro jazyk C ve výchozím nastavení bez zavedení zásadních změn ve stabilních jazykových verzích. Visual Studio 2022 verze 17.2 a novější přidávají možnost shody /Zc:__STDC__
, která definuje toto makro. Neexistuje žádná záporná verze možnosti. V současné době plánujeme tuto možnost používat ve výchozím nastavení pro budoucí verze jazyka C.
Tato změna narušuje kompatibilitu se zdrojem. Platí, pokud je povolen režim C11 nebo C17 (/std:c11
nebo /std:c17
) a /Zc:__STDC__
je zadán.
Příklad
// 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__
*/
Upozornění na chybějící složené závorky
Upozornění C5246 oznamuje chybějící složené závorky při agregované inicializaci podobjektu. Před verzí 17.2 sady Visual Studio 2022 neřešilo upozornění případ anonymního struct
nebo union
.
Tato změna narušuje kompatibilitu se zdrojem. Platí, když je povolené upozornění C5246, které je ve výchozím nastavení vypnuté.
Příklad
V sadě Visual Studio 2022 verze 17.2 a novější teď tento kód způsobí chybu:
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
*/
Pokud chcete tento problém vyřešit, přidejte do inicializátoru složené závorky:
void f()
{
S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Vylepšení souladu v sadě Visual Studio 2022 verze 17.1
Visual Studio 2022 verze 17.1 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Detekce špatně utvořeného výchozího zachycení v nelokálních lambda výrazech
Standard jazyka C++ umožňuje, aby výraz lambda v oboru bloku měl výchozí hodnotu capture. Ve Visual Studio 2022 verze 17.1 a novější kompilátor zjistí, kdy v nelokálním lambda výrazu není povoleno výchozí zachytávání. Vygeneruje nové upozornění na úroveň 4, C5253.
Tato změna narušuje kompatibilitu se zdrojem. Platí v jakémkoli režimu, který používá nový procesor lambda: /Zc:lambda
, /std:c++20
nebo /std:c++latest
.
Příklad
V sadě Visual Studio 2022 verze 17.1 teď tento kód vygeneruje chybu:
#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; };
// ^
Pokud chcete tento problém vyřešit, odeberte výchozí zachytávání:
#pragma warning(error:5253)
auto incr = [](int value) { return value + 1; };
C4028 je teď C4133 pro operace z funkce na ukazatel
Před verzí 17.1 sady Visual Studio 2022 kompilátor oznámil nesprávnou chybovou zprávu u určitých porovnání ukazatelů na funkci v kódu jazyka C. Nesprávná zpráva byla hlášena při porovnání dvou ukazatelů funkce, které měly stejné počty argumentů, ale nekompatibilní typy. Nyní vydáváme jiné upozornění, které si stěžuje na nekompatibilitu ukazatele na funkci, a ne na neshodu parametrů funkce.
Tato změna narušuje kompatibilitu se zdrojem. Platí, když je kód zkompilován jako C.
Příklad
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)'
Chyba v nezávislém komponentu static_assert
Ve Visual Studiu 2022 verze 17.1 a novější, pokud výraz spojený s static_assert
není závislým výrazem, kompilátor vyhodnotí výraz během jeho analýzy. Pokud se výraz vyhodnotí jako false
, kompilátor vygeneruje chybu. Dříve, pokud byl static_assert
v těle šablony funkce (nebo v těle členské funkce šablony třídy), kompilátor tuto analýzu neprováděl.
Tato změna narušuje kompatibilitu se zdrojem. Platí v jakémkoli režimu, který znamená /permissive-
nebo /Zc:static_assert
. Tuto změnu chování lze zakázat pomocí možnosti kompilátoru /Zc:static_assert-
.
Příklad
V sadě Visual Studio 2022 verze 17.1 a novější teď tento kód způsobí chybu:
template<typename T>
void f()
{
static_assert(false, "BOOM!");
}
Pokud chcete tento problém vyřešit, nastavte výraz jako závislý. Příklad:
template<typename>
constexpr bool dependent_false = false;
template<typename T>
void f()
{
static_assert(dependent_false<T>, "BOOM!");
}
Při této změně kompilátor generuje chybu pouze v případě vytvoření instance šablony f
funkce.
Zlepšení shody v prostředí Visual Studio 2022 verze 17.0
Visual Studio 2022 verze 17.0 obsahuje následující vylepšení shody, opravy chyb a změny chování v kompilátoru Microsoft C/C++.
Upozornění na šířku bitového pole pro typ výčtu
Když deklarujete instanci typu výčtu jako bitové pole, šířka bitového pole musí obsahovat všechny možné hodnoty výčtu. V opačném případě kompilátor vydá diagnostickou zprávu. Podívejte se na tento příklad: Zvažte:
enum class E : unsigned { Zero, One, Two };
struct S {
E e : 1;
};
Programátor může očekávat, že člen S::e
třídy může obsahovat libovolný z explicitně pojmenovaných enum
hodnot. Vzhledem k počtu prvků výčtu není možné. Bitové pole nemůže pokrýt rozsah explicitně zadaných hodnot E
(koncepčně jde o doménuE
). Pokud chcete vyřešit problém, že šířka bitového pole není dostatečně velká pro doménu výčtu, přidá se do MSVC nové upozornění (ve výchozím nastavení vypnuto):
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 };
^
Toto chování kompilátoru představuje zdrojovou a binární nekompatibilní změnu, která ovlivňuje všechny režimy /std
i /permissive
.
Chyba při porovnání seřazených ukazatelů proti nullptr
nebo 0.
Standard C++ neúmyslně umožnil seřazené porovnání ukazatele proti nullptr
nebo 0. Příklad:
bool f(int *p)
{
return p >= 0;
}
Dokument WG21 N3478 tento dohled odstranil. Tato změna se implementuje v MSVC. Při kompilaci příkladu pomocí /permissive-
(a /diagnostics:caret
) se vygeneruje následující chyba:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
return p >= 0;
^
Toto chování kompilátoru představuje změnu, která narušuje zdrojový a binární kód zkompilovaný pomocí /permissive-
ve všech režimech /std
.