Ulepszenia zgodności języka C++, zmiany zachowania i poprawki błędów w programie Visual Studio 2022
Język Microsoft C/C++ w programie Visual Studio (MSVC) wprowadza ulepszenia zgodności i poprawki błędów w każdej wersji. W tym artykule wymieniono znaczące ulepszenia według wersji głównej, a następnie według wersji. Aby przejść bezpośrednio do zmian dla określonej wersji, użyj linków w tym artykule .
Ten dokument zawiera listę zmian w programie Visual Studio 2022.
Aby uzyskać informacje o zmianach w programie Visual Studio 2019, zobacz Ulepszenia zgodności języka C++ w programie Visual Studio 2019.
Aby uzyskać informacje o zmianach w programie Visual Studio 2017, zobacz Ulepszenia zgodności języka C++ w programie Visual Studio 2017.
Aby uzyskać informacje o zmianach w starszych wersjach, zobacz Visual C++ What's New 2003–2015 (Co nowego w programie Visual C++ do 2015 r.).
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.11
Program Visual Studio 2022 w wersji 17.11 ma następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze Microsoft C/C++.
Szczegółowe podsumowanie zmian wprowadzonych w standardowej bibliotece szablonów, w tym zmian zgodności, poprawek błędów i ulepszeń wydajności, można znaleźć w dokumencie STL Changelog VS 2022 17.11.
Drukuj puste wiersze za pomocą polecenia println
Na P3142R0 można teraz łatwo wygenerować pusty wiersz za pomocą polecenia println
. Ta funkcja jest dostępna podczas kompilowania za pomocą /std:c++latest
polecenia .
Przed tą zmianą napisałeś: println("");
Teraz piszesz: println();
.
println();
jest odpowiednikiemprintln(stdout);
println(FILE* stream);
jest odpowiednikiemprintln(stream, "\n");
Zaimplementowana range_formatter
Na P2286R8range_formatter
jest teraz implementowana. Ta funkcja jest dostępna podczas kompilowania za pomocą /std:c++latest
polecenia .
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.10
Program Visual Studio 2022 w wersji 17.10 ma następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Szczegółowe podsumowanie zmian wprowadzonych w standardowej bibliotece szablonów, w tym zmian zgodności, poprawek błędów i ulepszeń wydajności, można znaleźć w temacie STL Changelog VS 2022 17.10.
Specjalizacja operatora konwersji z jawnie określonym typem zwrotnym
Kompilator używany do niepoprawnego specjalizowania operatorów konwersji, co może prowadzić do niezgodności typu zwracanego. Te nieprawidłowe specjalizacje już się nie zdarzają. Jest to zmiana powodująca niezgodność kodu źródłowego.
// 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
}
Dodano obsługę parametrów #elifdef
i #elifndef
Dodano obsługę WG21 P2334R1 (C++23) i WG14 N2645 (C++23), które wprowadziły #elifdef
dyrektywy preprocesora i #elifndef
.
Wymaga /std:clatest
lub /std:c++latest
.
Przed:
#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
Stosowanie typu _Alignas
strukturalnego w języku C
Dotyczy języka C (C17 i nowszych). Dodano również do programu Microsoft Visual Studio 17.9
W wersjach programu Visual C++ przed programem Visual Studio 2022 w wersji 17.9, jeśli _Alignas
specyfikator pojawił się obok typu strukturalnego w deklaracji, nie został poprawnie zastosowany zgodnie ze standardem 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");
Zgodnie ze standardem ISO-C ten kod powinien zostać skompilowany bez static_assert
emitowania diagnostyki.
Dyrektywa _Alignas
ma zastosowanie tylko do zmiennej składowej member1
. Nie może zmienić wyrównania obiektu struct Inner
. Jednak przed uruchomieniem programu Visual Studio 17.9.1 wyemitowano diagnostykę "nieprawidłowe wyrównanie". Kompilator wyrównany member2
do przesunięcia 32 bajtów w obrębie struct Outer
typu.
Jest to binarna zmiana powodująca niezgodność, więc ostrzeżenie jest teraz emitowane, gdy ta zmiana zostanie w życie. Ostrzeżenie C5274 jest teraz emitowane na poziomie ostrzeżenia 1 dla poprzedniego przykładu: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects)
.
Ponadto w poprzednich wersjach programu Visual Studio, gdy _Alignas
specyfikator pojawił się obok deklaracji typu anonimowego, został zignorowany.
// 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");
Wcześniej obie static_assert
instrukcje zakończyły się niepowodzeniem podczas kompilowania tego kodu. Teraz kod jest kompilowany, ale emituje następujące ostrzeżenia poziomu 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)
Aby uzyskać poprzednie zachowanie, zastąp element _Alignas(N)
.__declspec(align(N))
W przeciwieństwie do _Alignas
typu , declspec(align)
ma zastosowanie do typu .
Ulepszone ostrzeżenie C4706
Jest to zmiana powodująca niezgodność kodu źródłowego. Wcześniej kompilator nie wykrył konwencji zawijania przypisania w nawiasach, jeśli przypisanie było zamierzone, aby pominąć ostrzeżenie C4706 o przypisaniu w wyrażeniu warunkowym. Kompilator wykrywa teraz nawiasy i pomija ostrzeżenie.
#pragma warning(error: 4706)
struct S
{
auto mf()
{
if (value = 9)
return value + 4;
else
return value;
}
int value = 9;
};
Kompilator emituje teraz również ostrzeżenie w przypadkach, gdy funkcja nie jest przywołynięta. Wcześniej, ponieważ mf
jest funkcją śródliniową, do której nie odwołuje się odwołanie, ostrzeżenie C4706 nie zostało wyemitowane dla tego kodu. Teraz ostrzeżenie jest emitowane:
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
Aby naprawić to ostrzeżenie, użyj operatora równości , value == 9
jeśli jest to zamierzone. Lub zawijaj przypisanie w nawiasach, (value = 9)
, jeśli przypisanie jest zamierzone. W przeciwnym razie, ponieważ funkcja nie jest wnioskowana, usuń ją.
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.9
Program Visual Studio 2022 w wersji 17.9 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Aby uzyskać szersze podsumowanie zmian wprowadzonych w standardowej bibliotece szablonów, zobacz STL Changelog VS 2022 17.9.
Stosowanie typu _Alignas
strukturalnego w języku C
W wersjach programu Visual C++ przed programem Visual Studio 2022 w wersji 17.9, gdy _Alignas
obok typu struktury w deklaracji nie zastosowano go poprawnie zgodnie ze standardem ISO-C. Na przykład:
// 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");
Zgodnie ze standardem ISO-C ten kod powinien zostać skompilowany bez static_assert
emitowania diagnostyki. Dyrektywa _Alignas
ma zastosowanie tylko do zmiennej składowej member1
. Nie może zmienić wyrównania obiektu struct Inner
. Jednak przed wydaniem 17.9.1 programu Visual Studio emitowano diagnostykę "nieprawidłowe wyrównanie". Kompilator wyrównany member2
do przesunięcia 32 bajtów w obiekcie struct Outer
.
Naprawienie tej zmiany jest zmianą powodującą niezgodność binarną, więc po zastosowaniu tej zmiany zachowania jest emitowane ostrzeżenie. W poprzednim kodzie ostrzeżenie C5274 "_Alignas
nie ma już zastosowania do typu "Inner" (dotyczy tylko zadeklarowanych obiektów danych)" jest teraz emitowane na poziomie ostrzeżenia 1.
W poprzednich wersjach programu Visual Studio _Alignas
była ignorowana, gdy była wyświetlana obok deklaracji typu anonimowego. Na przykład:
// 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");
Wcześniej obie static_assert
instrukcje zakończyły się niepowodzeniem podczas kompilowania tego kodu. Kod jest teraz kompilowany, ale z następującymi ostrzeżeniami poziomu 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)
Jeśli chcesz użyć wcześniejszego zachowania, zastąp element _Alignas(N)
.__declspec(align(N))
W przeciwieństwie do _Alignas
elementu declspec(align)
można zastosować do typu.
__VA_OPT__
jest włączona jako rozszerzenie w obszarze /Zc:preprocessor
__VA_OPT__
dodano do języków C++20 i C23. Poprzednio, nie było standardowego sposobu, aby wyjąć przecinek w makrze wariadzkim. Aby zapewnić lepszą zgodność z poprzednimi wersjami, __VA_OPT__
jest włączona w ramach preprocesora /Zc:preprocessor
opartego na tokenach we wszystkich wersjach językowych.
Na przykład teraz kompiluje się bez błędu:
#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")
Język C23
W przypadku języka C23 podczas korzystania z przełącznika kompilatora /std:clatest
są dostępne następujące elementy:
Dostępne są następujące wersje dla wszystkich wersji językowych języka C:
Standardowa biblioteka C++
Funkcje języka C++23
formattable
,range_format
,format_kind
iset_debug_format()
w ramach P2286R8 zakresów formatowania<mdspan>
dla P0009R18 i kolejnych zmian sformułowań, które zostały zastosowane do języka C++23 Standard.format()
wskaźniki na P2510R3.
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.8
Program Visual Studio 2022 w wersji 17.8 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
/FU
problemy z błędem
Kompilator języka C używany do akceptowania /FU
opcji, mimo że nie obsługuje kompilacji zarządzanej od jakiegoś czasu. Teraz występuje błąd. Projekty, które przechodzą tę opcję, muszą ograniczyć ją tylko do projektów C++/CLI.
Standardowa biblioteka C++
Moduły std
nazwane języka C++23 są std.compat
teraz dostępne podczas kompilowania za pomocą /std:c++20
polecenia .
Aby uzyskać szersze podsumowanie zmian wprowadzonych w standardowej bibliotece języka C++, zobacz STL Changelog VS 2022 17.8.
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.7
Program Visual Studio 2022 w wersji 17.7 zawiera następujące wyróżnione ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Dodano /std:clatest
do kompilatora języka C
Ten przełącznik zachowuje się jak /std:c++latest
przełącznik dla kompilatora języka C++. Przełącznik włącza wszystkie obecnie zaimplementowane funkcje kompilatora i biblioteki standardowej proponowane dla następnego standardu C, a także niektóre funkcje w toku i eksperymentalne.
Standardowa biblioteka C++
Biblioteka jest teraz obsługiwana <print>
. Zobacz P2093R14 Sformatowane dane wyjściowe.
Zaimplementowano views::cartesian_product
.
Aby uzyskać szersze podsumowanie zmian wprowadzonych w standardowej bibliotece szablonów, zobacz STL Changelog VS 2022 17.7.
using
Zgodność
using
Wcześniej dyrektywa mogła spowodować, że nazwy z używanych przestrzeni nazw pozostaną widoczne, gdy nie powinny. Może to spowodować, że wyszukiwanie niekwalifikowanej nazwy będzie znajdować nazwę w przestrzeni nazw nawet wtedy, gdy nie ma using
aktywnej dyrektywy.
Oto kilka przykładów nowego i starego zachowania.
Odwołania w następujących komentarzach do "(1)" oznaczają wywołanie metody f<K>(t)
w przestrzeni nazw 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>());
}
}
Ten sam podstawowy problem może spowodować odrzucenie kodu, który został wcześniej skompilowany:
#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;
}
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.6
Program Visual Studio 2022 w wersji 17.6 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Przypisania złożone volatile
nie są już przestarzałe
C++20 przestarzałe stosowanie niektórych operatorów do typów kwalifikowanych za pomocą volatile
polecenia . Na przykład po skompilowaniu następującego kodu za pomocą cl /std:c++20 /Wall test.cpp
polecenia :
void f(volatile int& expr)
{
++expr;
}
Kompilator generuje element test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20
.
W języku C++20 operatory przypisania złożonego (operatory formularza @=
) były przestarzałe. W języku C++23 operatory złożone wykluczone w języku C++20 nie są już przestarzałe. Na przykład w języku C++23 następujący kod nie generuje ostrzeżenia, natomiast w języku C++20:
void f(volatile int& e1, int e2)
{
e1 += e2;
}
Aby uzyskać więcej informacji na temat tej zmiany, zobacz CWG:2654
Ponowne zapisywanie równości w wyrażeniach jest mniej zmian powodujących niezgodność (P2468R2)
W języku C++20 P2468R2 zmienił kompilator tak, aby akceptował kod, taki jak:
struct S
{
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} != S{};
Kompilator akceptuje ten kod, co oznacza, że kompilator jest bardziej rygorystyczny z kodem, takim jak:
struct S
{
operator bool() const;
bool operator==(const S&);
};
bool b = S{} == S{};
Wersja 17.5 kompilatora akceptuje ten program. Wersja 17.6 kompilatora go odrzuca. Aby rozwiązać ten problem, dodaj const
polecenie , aby operator==
usunąć niejednoznaczność. Możesz też dodać odpowiadający operator!=
definicji, jak pokazano w poniższym przykładzie:
struct S
{
operator bool() const;
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} == S{};
Kompilator Microsoft C/C++ w wersjach 17.5 i 17.6 akceptuje poprzedni program i wywołuje obie S::operator==
wersje.
Ogólny model programowania opisany w P2468R2 polega na tym, że jeśli istnieje odpowiedni operator!=
typ, zazwyczaj pomija zachowanie ponownego zapisywania. Dodanie odpowiadającego operator!=
mu poprawki jest sugerowaną poprawką dla kodu, który został wcześniej skompilowany w języku C++17. Aby uzyskać więcej informacji, zobacz Model programowania.
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.4
Program Visual Studio 2022 w wersji 17.4 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Podstawowe typy niezakresowe enum
bez stałego typu
W wersjach programu Visual Studio przed programem Visual Studio 2022 w wersji 17.4 kompilator języka C++ nie określił poprawnie bazowego typu wyliczenia niezakresowego bez stałego typu podstawowego. W obszarze /Zc:enumTypes
, teraz poprawnie implementujemy standardowe zachowanie.
Język C++ Standard wymaga, aby podstawowy typ obiektu enum
był wystarczająco duży, aby przechowywać wszystkie moduły wyliczające w tym obiekcie enum
. Wystarczająco duże moduły wyliczania mogą ustawić bazowy typ enum
elementu na unsigned int
, long long
lub unsigned long long
. Wcześniej takie enum
typy zawsze miały podstawowy typ int
w kompilatorze firmy Microsoft, niezależnie od wartości modułu wyliczającego.
Po włączeniu /Zc:enumTypes
tej opcji jest potencjalna zmiana powodująca niezgodność źródła i danych binarnych. Jest ona domyślnie wyłączona i nie jest włączona przez /permissive-
usługę , ponieważ poprawka może mieć wpływ na zgodność binarną. Niektóre typy wyliczenia zmieniają rozmiar po włączeniu zgodnej poprawki. Niektóre nagłówki zestawu Windows SDK zawierają takie definicje wyliczenia.
Przykład
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 modułów wyliczania w enum
definicji bez stałego typu bazowego
W wersjach programu Visual Studio przed programem Visual Studio 2022 w wersji 17.4 kompilator języka C++ nie poprawnie modeluje typów modułów wyliczania. Można założyć, że nieprawidłowy typ w wyliczeniach bez stałego typu bazowego przed zamykającym nawiasem klamrowym wyliczenia. W obszarze /Zc:enumTypes
kompilator prawidłowo implementuje standardowe zachowanie.
Język C++ Standard określa, że w definicji wyliczenia bez stałego typu bazowego inicjatory określają typy modułów wyliczających. Lub dla modułów wyliczania bez inicjatora, według typu poprzedniego modułu wyliczającego (ewidencjonowanie przepełnienia). Wcześniej takie wyliczenia zawsze miały typ wyliczenia z symbolem zastępczym dla typu bazowego (zazwyczaj int
).
Po włączeniu /Zc:enumTypes
tej opcji jest potencjalna zmiana powodująca niezgodność źródła i danych binarnych. Jest ona domyślnie wyłączona i nie jest włączona przez /permissive-
usługę , ponieważ poprawka może mieć wpływ na zgodność binarną. Niektóre typy wyliczenia zmieniają rozmiar po włączeniu zgodnej poprawki. Niektóre nagłówki zestawu Windows SDK zawierają takie definicje wyliczenia.
Przykład
enum Enum {
A = 'A',
B = sizeof(A)
};
static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes
W tym przykładzie moduł A
wyliczający powinien mieć typ char
przed zamykającym nawiasem klamrowym wyliczenia, więc B
należy zainicjować przy użyciu polecenia sizeof(char)
. Przed poprawką /Zc:enumTypes
miał A
typ Enum
wyliczenia z wydukowanym typem int
bazowym , i B
został zainicjowany przy użyciu , sizeof(Enum)
lub 4.
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.3
Program Visual Studio 2022 w wersji 17.3 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
C: Ulepszone sprawdzanie zgodności modyfikatora między wskaźnikami
Kompilator języka C nie porównywał prawidłowo modyfikatorów między wskaźnikami, zwłaszcza void*
. Ta usterka może spowodować nieprawidłową diagnostykę niezgodności między elementami i i zgodnością między const int**
int* volatile*
void*
i .void*
Przykład
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
}
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.2
Program Visual Studio 2022 w wersji 17.2 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Nieokreślone ostrzeżenia o znakach dwukierunkowych
Program Visual Studio 2022 w wersji 17.2 dodaje ostrzeżenie poziomu 3 C5255 dla nieokreślonych znaków dwukierunkowych Unicode w komentarzach i ciągach. Ostrzeżenie dotyczy problemu bezpieczeństwa opisanego w Trojan Source: Invisible Vulnerabilities autorstwa Nicholasa Bouchera i Rossa Andersona. Aby uzyskać więcej informacji na temat znaków dwukierunkowych Unicode, zobacz Unicode Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM (Załącznik standardowy Unicode® nr 9: ALGORYTM DWUKIERUNKOWY UNICODE).
Ostrzeżenie C5255 dotyczy tylko plików, które po konwersji zawierają znaki dwukierunkowe Unicode. To ostrzeżenie dotyczy plików UTF-8, UTF-16 i UTF-32, więc należy podać odpowiednie kodowanie źródłowe. Ta zmiana jest zmianą powodującą niezgodność źródła.
Przykład (przed/po)
W wersjach programu Visual Studio przed programem Visual Studio 2022 w wersji 17.2 nieokreślony znak dwukierunkowy nie wygenerował ostrzeżenia. Program Visual Studio 2022 w wersji 17.2 generuje ostrzeżenie C5255:
// bidi.cpp
int main() {
const char *access_level = "user";
// The following source line contains bidirectional Unicode characters equivalent to:
// if ( strcmp(access_level, "user\u202e \u2066// Check if admin \u2069 \u2066") ) {
// In most editors, it's rendered as:
// if ( strcmp(access_level, "user") ) { // Check if admin
if ( strcmp(access_level, "user // Check if admin ") ) {
printf("You are an admin.\n");
}
return 0;
}
/* build output
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+202e'
bidi.cpp(8): warning C5255: unterminated bidirectional character encountered: 'U+2066'
*/
from_chars()
float
tiebreaker
Program Visual Studio 2022 w wersji 17.2 naprawia usterkę w <charconv>
from_chars()
float
regułach tiebreaker, które wygenerowały nieprawidłowe wyniki. Ta usterka dotyczyła ciągów dziesiętnych, które znajdowały się dokładnie w połowie kolejnych float
wartości w wąskim zakresie. (Najmniejsze i największe wartości, których dotyczy problem, to 32768.009765625
i 131071.98828125
, odpowiednio). Reguła tiebreaker chciała zaokrąglić wartość "parzysta", a "nawet" miała wartość "w dół", ale implementacja niepoprawnie zaokrąglona "w górę" (double
nie miała to wpływu). Aby uzyskać więcej informacji i szczegółów implementacji, zobacz microsoft/STL#2366.
Ta zmiana wpływa na zachowanie środowiska uruchomieniowego w określonym zakresie przypadków:
Przykład
// 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");
}
W wersjach przed programem Visual Studio 2022 w wersji 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.
W programie Visual Studio 2022 w wersji 17.2 i po:
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__
udostępnia __STDC__
język C
Standard C wymaga, aby zgodna implementacja języka C definiuje __STDC__
jako 1
. Ze względu na zachowanie funkcji UCRT, która nie uwidacznia funkcji POSIX, gdy __STDC__
jest 1
, nie jest możliwe zdefiniowanie tego makra dla języka C domyślnie bez wprowadzania zmian powodujących niezgodność do stabilnych wersji językowych. Program Visual Studio 2022 w wersji 17.2 lub nowszej dodaje opcję /Zc:__STDC__
zgodności, która definiuje to makro. Nie ma negatywnej wersji opcji. Obecnie planujemy domyślnie używać tej opcji dla przyszłych wersji języka C.
Ta zmiana jest zmianą powodującą niezgodność źródła. Ma zastosowanie, gdy tryb C11 lub C17 jest włączony (/std:c11
lub /std:c17
) i /Zc:__STDC__
jest określony.
Przykład
// 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__
*/
Ostrzeżenie dotyczące brakujących nawiasów klamrowych
Ostrzeżenie C5246 zgłasza brak nawiasów klamrowych podczas agregacji inicjowania podobiektu. Przed programem Visual Studio 2022 w wersji 17.2 ostrzeżenie nie obsłużyło przypadku anonimowego struct
lub union
.
Ta zmiana jest zmianą powodującą niezgodność źródła. Ma zastosowanie, gdy jest włączone ostrzeżenie off-by-default C5246.
Przykład
W programie Visual Studio 2022 w wersji 17.2 lub nowszej ten kod powoduje teraz błąd:
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
*/
Aby rozwiązać ten problem, dodaj nawiasy klamrowe do inicjatora:
void f()
{
S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.1
Program Visual Studio 2022 w wersji 17.1 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Wykrywanie wartości domyślnej przechwytywania nielokalnego wyrażenia lambda
Język C++ Standard zezwala tylko na wyrażenie lambda w zakresie bloku na wartość domyślną przechwytywania. W programie Visual Studio 2022 w wersji 17.1 lub nowszej kompilator wykrywa, gdy ustawienie domyślne przechwytywania nie jest dozwolone w nielokalnym wyrażeniu lambda. Emituje nowe ostrzeżenie poziomu 4, C5253.
Ta zmiana jest zmianą powodującą niezgodność źródła. Ma zastosowanie w dowolnym trybie, który używa nowego procesora lambda: /Zc:lambda
, /std:c++20
lub /std:c++latest
.
Przykład
W programie Visual Studio 2022 w wersji 17.1 ten kod generuje teraz błąd:
#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; };
// ^
Aby rozwiązać ten problem, usuń ustawienie domyślne przechwytywania:
#pragma warning(error:5253)
auto incr = [](int value) { return value + 1; };
C4028 jest teraz C4133 dla operacji funkcji do wskaźnika
Przed programem Visual Studio 2022 w wersji 17.1 kompilator zgłosił niepoprawny komunikat o błędzie w niektórych porównaniach wskaźników do funkcji w kodzie języka C. Niepoprawny komunikat został zgłoszony podczas porównywania dwóch wskaźników funkcji, które miały te same liczby argumentów, ale niezgodne typy. Teraz wydajemy inne ostrzeżenie, które skarży się na niezgodność wskaźnika do funkcji, a nie niezgodność parametrów funkcji.
Ta zmiana jest zmianą powodującą niezgodność źródła. Ma zastosowanie, gdy kod jest kompilowany jako C.
Przykład
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)'
Błąd w przypadku niezależności static_assert
W programie Visual Studio 2022 w wersji 17.1 lub nowszej, jeśli wyrażenie skojarzone z wyrażeniem nie jest wyrażeniem static_assert
zależnym, kompilator oblicza wyrażenie podczas jego analizowania. Jeśli wyrażenie zwróci wartość false
, kompilator emituje błąd. Wcześniej, jeśli element static_assert
znajdował się w treści szablonu funkcji (lub w treści funkcji składowej szablonu klasy), kompilator nie wykonałby tej analizy.
Ta zmiana jest zmianą powodującą niezgodność źródła. Ma zastosowanie w dowolnym trybie, który implikuje /permissive-
lub /Zc:static_assert
. Tę zmianę zachowania można wyłączyć przy użyciu opcji kompilatora /Zc:static_assert-
.
Przykład
W programie Visual Studio 2022 w wersji 17.1 lub nowszej ten kod powoduje teraz błąd:
template<typename T>
void f()
{
static_assert(false, "BOOM!");
}
Aby rozwiązać ten problem, ustaw wyrażenie na zależne. Na przykład:
template<typename>
constexpr bool dependent_false = false;
template<typename T>
void f()
{
static_assert(dependent_false<T>, "BOOM!");
}
Dzięki tej zmianie kompilator emituje błąd tylko wtedy, gdy szablon f
funkcji zostanie utworzone.
Ulepszenia zgodności w programie Visual Studio 2022 w wersji 17.0
Program Visual Studio 2022 w wersji 17.0 zawiera następujące ulepszenia zgodności, poprawki błędów i zmiany zachowania w kompilatorze microsoft C/C++.
Ostrzeżenie dotyczące szerokości pola bitowego dla typu wyliczenia
W przypadku deklarowania wystąpienia typu wyliczenia jako pola bitowego szerokość pola bitowego musi pomieścić wszystkie możliwe wartości wyliczenia. W przeciwnym razie kompilator wysyła komunikat diagnostyczny. Rozważmy następujący przykład: Rozważ następujące kwestie:
enum class E : unsigned { Zero, One, Two };
struct S {
E e : 1;
};
Programista może oczekiwać, że składowa S::e
klasy będzie przechowywać dowolną jawnie nazwaną enum
wartość. Biorąc pod uwagę liczbę elementów wyliczenia, nie jest to możliwe. Pole bitowe nie może obejmować zakresu jawnie podanych wartości E
(koncepcyjnie domeny E
). Aby rozwiązać problem, że szerokość pola bitowego nie jest wystarczająco duża dla domeny wyliczenia, nowe (domyślnie wyłączone) ostrzeżenie jest dodawane do MSVC:
t.cpp(4,5): warning C5249: 'S::e' of type 'E' has named enumerators with values that cannot be represented in the given bit field width of '1'.
E e : 1;
^
t.cpp(1,38): note: see enumerator 'E::Two' with value '2'
enum class E : unsigned { Zero, One, Two };
^
To zachowanie kompilatora to źródłowa i binarna zmiana powodująca niezgodność, która ma wpływ na wszystkie /std
tryby i /permissive
.
Błąd podczas porównywania uporządkowanego wskaźnika względem nullptr
lub 0
Standard C++ przypadkowo zezwalał na uporządkowane porównanie wskaźników względem nullptr
lub 0. Na przykład:
bool f(int *p)
{
return p >= 0;
}
WG21 papier N3478 usunął ten nadzór. Ta zmiana jest implementowana w MSVC. Gdy przykład jest kompilowany przy użyciu metody /permissive-
(i /diagnostics:caret
), emituje następujący błąd:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
return p >= 0;
^
To zachowanie kompilatora jest zmianą powodującą niezgodność źródłową i binarną, która ma wpływ na kod skompilowany przy użyciu /permissive-
we wszystkich /std
trybach.