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.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 _Alignaselementu 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:

typeof
typeof_unqual

Dostępne są następujące wersje dla wszystkich wersji językowych języka C:

__typeof__
__typeof_unqual__

Standardowa biblioteka C++

Funkcje języka C++23

  • formattable, range_format, format_kindi set_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++20polecenia .

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ą volatilepolecenia . Na przykład po skompilowaniu następującego kodu za pomocą cl /std:c++20 /Wall test.cpppolecenia :

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 longlub 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:enumTypeskompilator 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 intbazowym , 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 lub /std:c11/std:c17, wraz z /Zc:__STDC__.

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++20lub /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 domenyE). 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.

Zobacz też

Zgodność języka Microsoft C/C++