Aracılığıyla paylaş


Visual Studio 2022'de C++ Uyumluluk geliştirmeleri, davranış değişiklikleri ve hata düzeltmeleri

Visual Studio'da (MSVC) Microsoft C/C++ her sürümde uyumluluk iyileştirmeleri ve hata düzeltmeleri yapar. Bu makalede, ana sürüme ve sonra sürüme göre yapılan önemli iyileştirmeler listelenmiştir. Belirli bir sürümdeki değişikliklere doğrudan atlamak için, bu makalenin üst kısmındaki Bu makaledeki bağlantıları kullanın.

Bu belgede Visual Studio 2022'deki değişiklikler listelenir.

Visual Studio'nun önceki sürümlerindeki değişiklikler için:

Sürüm Uyumluluk geliştirmeleri bağlantısı
2019 Visual Studio 2019'da C++ uyumluluğu geliştirmeleri
2017 Visual Studio 2017’deki C++ uyumluluk geliştirmeleri
2003-2015 Visual C++ 2003 ile 2015 Arasındaki Farklar

Visual Studio 2022 sürüm 17.14'te uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.14, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Uyumluluk geliştirmeleri

  • Standart kitaplık sağlamlaştırma (P3471R4), standart kitaplıktaki bazı tanımsız davranış örneklerini __fastfail çağrısına dönüştürür. Varsayılan olarak kapalı. Proje genelinde etkinleştirmek için _MSVC_STL_HARDENING=1 tanımlayın.

Gelişmiş davranış

  • Kullanımdan sonra yapılan hataları azaltmak için "yok edici mezar taşları" uygulandı. Varsayılan olarak kapalı. Proje genelinde etkinleştirmek için _MSVC_STL_DESTRUCTOR_TOMBSTONES=1 tanımlayın.

Hata düzeltmeleri

  • CUDA projesinde <format> kullanılırken oluşan hatalı derleyici hataları düzeltildi.

  • Derleme sırasında yerel bir değişkenin adresinin istemeden açığa çıkabileceği bir sorunu düzelttik. Örneğin:

    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
    

    Örnek #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
    }
    
  • /permissive- ile derlenen kod, artık bir bildirgede friend ve static birleşimini kabul etmemektedir. Genellikle düzeltme, static'yu bildirimden kaldırmaktır. Örneğin:

    struct S
    {
        friend static void f(); // Previously accepted, now emits error C2440: 'static' cannot be used with 'friend'
    };
    
  • Geçici nitelikli türlere referans bağlama, temel veya türetilmiş bir sınıfa başvuru yapıldığında düzeltildi. Örneğin:

    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.
    

Uyumluluk değişiklikleri, hata düzeltmeleri ve performans geliştirmeleri de dahil olmak üzere Standart Şablon Kitaplığı'nda yapılan değişikliklerin ayrıntılı bir özeti için bkz. STL Changelog VS 2022 17.14.

Visual Studio 2022 sürüm 17.13'te uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.13, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Uyumluluk değişiklikleri, hata düzeltmeleri ve performans geliştirmeleri dahil olmak üzere Standart Şablon Kitaplığı'nda yapılan değişikliklerin ayrıntılı bir özeti için bkz. STL Changelog VS 2022 17.13.

Argümana bağlı arama (ADL)

Dil yapıları, range-for ve yapılandırılmış bağlamalar gibi, begin, endveya getgibi belirli tanımlayıcılar için bağımsız değişkene bağlı özel arama kurallarına sahiptir. Daha önce bu arama, bağımsız değişkene bağımlı arama için normalde ilişkili ad alanları kümesine dahil olmasa bile std ad alanındaki adayları std ad alanına dahil ediyordu.

Bu yapılar için std bildirimleri getiren programlar artık derlenmez. Bunun yerine, bildirimlerin söz konusu türler (büyük olasılıkla genel ad alanı dahil) için normal bir ilişkili ad alanında olması gerekir.

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

Uygulama tarafından ayrılmış makroları değiştiremezsiniz

Daha önce, derleyici _MSC_EXTENSIONSgibi uygulama tarafından sağlanan bazı makroları değiştirmeye veya tanımlamayı kaldırmaya izin verdi. Belirli makroların tanımını değiştirmek tanımsız davranışa neden olabilir.

Bazı ayrılmış makro adlarını değiştirmeye veya tanımlarını kaldırmaya çalışmak artık birinci seviye uyarı C5308ile sonuçlanacak. /permissive- modunda bu uyarı hata olarak değerlendirilir.

#undef _MSC_EXTENSIONS // Warning C5308: Modifying reserved macro name `_MSC_EXTENSIONS` may cause undefined behavior

Visual Studio 2022 sürüm 17.12'de uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.12, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Uyumluluk değişiklikleri, hata düzeltmeleri ve performans geliştirmeleri de dahil olmak üzere Standart Şablon Kitaplığı'nda yapılan değişikliklerin ayrıntılı bir özeti için bkz . STL Changelog VS 2022 17.12.

_com_ptr_t::operator bool() artık açık

Bu, kaynak veya ikili düzeyde uyumsuzluğa neden olan bir değişikliktir.

bool örneklerinden _com_ptr_t'ye yapılan örtük dönüşümler şaşırtıcı olabilir veya derleyici hatalarına yol açabilir. C.164: C++ Çekirdek Yönergelerinde örtük dönüştürme işleçlerinden kaçının ve bu kapsamda örtük dönüştürme işlevleri de önerilmez. Ve _com_ptr_t, hem bool hem de Interface* için örtük dönüştürmeler içeriyordu. Bu iki örtük dönüştürme belirsizliğe yol açabilir.

Bu sorunu çözmek için bool dönüştürme işlemi artık belirgin. Dönüştürme Interface* de değişiklik yok.

Bu yeni davranışı geri çevirmek ve önceki örtük dönüştürmeyi geri yüklemek için bir makro sağlanır. Bu değişiklikten vazgeçmek için /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL ile derleyin. Kodu örtük dönüştürmelere bağlı olmayacak şekilde değiştirmenizi öneririz.

Örneğin:

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

Sabit ifadeler artık her zaman noexcept izin verme modunda değil

Bu, kaynak veya ikili düzeyde uyumsuzluğa neden olan bir değişikliktir.

Sabit bir ifade, bir hata fırlatabilme ihtimali olan bir özel durum belirtimiyle bildirilmiş bir fonksiyona işlev çağrısını içerse bile her zaman noexcept kalırdı. Bu ifade C++17'de kaldırıldı, ancak Microsoft Visual C++ derleyicisi bunu tüm C++ dil sürümlerinde modda desteklemeye devam etti /permissive .

Bu /permissive mod davranışı kaldırıldı. Sabit ifadelere artık özel örtük davranışlar verilmez.

noexcept İşlevlerdeki constexpr tanımlayıcıya artık tüm modlarda uyuldu. Bu değişiklik, standart noexcept davranışı kullanan sonraki temel sorun çözümlerinin doğru uygulanması için gereklidir.

Örneğin:

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

Visual Studio 2022 sürüm 17.11'de uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.11, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Uyumluluk değişiklikleri, hata düzeltmeleri ve performans geliştirmeleri de dahil olmak üzere Standart Şablon Kitaplığı'nda yapılan değişikliklerin ayrıntılı bir özeti için bkz . STL Changelog VS 2022 17.11.

P3142R0'e göre, artık ile boş bir satır oluşturmak kolaydır. Bu özellik /std:c++latest ile derlenirken kullanılabilir. Bu değişiklik öncesinde şunu yazdınız: println(""); Şimdi şunu yazacaksınız: println();.

  • println(); eşdeğerdir println(stdout);
  • println(FILE* stream); eşdeğerdir println(stream, "\n");

Uygulanan range_formatter

P2286R8 uyarınca range_formatter artık uygulandı. Bu özellik /std:c++latest ile derlenirken kullanılabilir.

Visual Studio 2022 sürüm 17.10'da uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.10, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Uyumluluk değişiklikleri, hata düzeltmeleri ve performans geliştirmeleri de dahil olmak üzere Standart Şablon Kitaplığı'nda yapılan değişikliklerin ayrıntılı bir özeti için bkz . STL Changelog VS 2022 17.10.

Açıkça belirtilen dönüş türüyle dönüştürme işleci özelleştirmesi

Bazı durumlarda dönüştürme işleçlerini yanlış özelleştirmek için kullanılan derleyici, eşleşmeyen bir dönüş türüne yol açabilir. Bu geçersiz özelleştirmeler artık gerçekleşmez. Bu, kaynak kodunun işleyişinde aksamalara neden olan bir değişikliktir.

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

#elifdef ve #elifndef için destek eklendi

WG21 P2334R1 (C++23) ve WG14 N2645 (C++23) ile tanıtılan #elifdef ve #elifndef ön işlemci yönergeleri için destek eklendi. /std:clatest veya /std:c++latest gerektirir.

Önce:

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

Sonra:

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

_Alignas yapılandırılmış bir türde C'de uygulaması

C dili (C17 ve üzeri) için geçerlidir. Microsoft Visual Studio 17.9'a da eklendi

Visual Studio 2022 sürüm 17.9'dan önceki Visual C++ sürümlerinde, _Alignas bir bildirgede yapısal bir türün hemen yanında görünürse, ISO-C Standardına göre doğru uygulanmamıştır.

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

ISO-C Standardına göre, bu kod herhangi bir uyarı iletisi vermeden static_assert derlenmelidir.

yönergesi _Alignas yalnızca üye değişkenine member1uygulanır. struct Inner hizalamasını değiştirmemelidir. Ancak Visual Studio 17.9.1'den önce, "yanlış hizalama" tanılama mesajı üretiliyordu. Derleyici, member2'yi struct Outer türü içinde 32 baytlık bir ofsete hizaladı.

Bu ikili uyumsuz bir değişiklik olduğundan, bu değişiklik geçerli olduğunda bir uyarı verilir. Uyarı C5274 artık önceki örnek için uyarı düzeyi 1'de gösteriliyor: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects).

Ayrıca, Visual Studio'nun önceki sürümlerinde, _Alignas belirteci anonim bir tür tanımlayıcısı yanında göründüğünde, dikkate alınmadı.

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

Daha önce bu kod derlendiğinde her iki deyim de static_assert hata verdi. Şimdi kod derlenir, ancak aşağıdaki düzey 1 uyarılarını yayar:

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)

Önceki davranışı elde etmek için _Alignas(N) ile __declspec(align(N))'yi değiştirin. _Alignas'den farklı olarak, declspec(align) türe uygulanır.

Geliştirilmiş uyarı C4706

Bu, kaynak kodunun işleyişinde aksamalara neden olan bir değişikliktir. Önceden derleyici, atama amaçlandıysa, koşullu ifadede atama için C4706 uyarısını bastırmak amacıyla atamayı parantez içine alma geleneğini algılamadı. Derleyici artık parantezleri algılar ve uyarıyı bastırır.

#pragma warning(error: 4706)

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

   int value = 9;
};

Derleyici artık işleve başvurulmadığı durumlarda da uyarıyı yayar. Daha önce, mf başvurulmadığı bir satır içi işlev olduğundan, bu kod için C4706 uyarısı gösterilmiyordu. Şimdi uyarı yayılıyor:

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

Bu uyarıyı düzeltmek için, amaçlanan buysa eşitlik işleci olan value == 9'yı kullanın. Ya da atama amaçlanıyorsa, atamayı parantez içinde (value = 9) sarın. Aksi takdirde, işlev referans verilmediğinden kaldırın.

Visual Studio 2022 sürüm 17.9'da uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.9, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Standart Şablon Kitaplığı'na yapılan değişikliklerin daha geniş bir özeti için bkz . STL Changelog VS 2022 17.9.

_Alignas yapılandırılmış bir türde C'de uygulaması

Visual Studio 2022 sürüm 17.9'dan önceki Visual C++ sürümlerinde, _Alignas bir bildirimde bir yapı türünün yanında göründüğünde, ISO-C Standardına göre doğru uygulanmadı. Örneğin:

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

ISO-C Standardına göre, bu kod tanı mesajı vermeden static_assert derlenebilmelidir. yönergesi _Alignas yalnızca üye değişkenine member1uygulanır. struct Inner hizalamasını değiştirmemelidir. Ancak, Visual Studio'nun 17.9.1 sürümünden önce 'yanlış hizalama' tanısı verildi. Derleyici member2'yi struct Outer içinde 32 bayt kaymayla hizaladı.

Bunu düzeltmek, ikili uyumluluğu bozan bir değişiklik olduğundan, davranıştaki bu değişiklik uygulandığında bir uyarı verilir. Önceki kod için, Uyarı C5274, "_Alignas artık 'Inner' türüne uygulanmaz (yalnızca bildirilen veri nesneleri için geçerlidir)" uyarı düzeyi 1'de verilmektedir.

Visual Studio’nun önceki sürümlerinde, _Alignas anonim tip bildiriminin yanında göründüğünde yoksayıldı. Örneğin:

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

Daha önce bu kod derlendiğinde her iki deyim de static_assert hata verdi. Kod şimdi derlenir, ancak aşağıdaki düzey 1 uyarılarıyla birlikte:

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)

Önceki davranışı istiyorsanız, _Alignas(N)'i __declspec(align(N)) ile değiştirin. _Alignas'nün aksine, declspec(align) bir türe uygulanabilir.

__VA_OPT__, /Zc:preprocessor altında bir uzantı olarak etkinleştirildi.

__VA_OPT__ C++20 ve C23'e eklendi. Eklenmesinden önce, variadic makroda bir virgülü ihmal etmenin standart bir yolu yoktu. Geriye dönük daha iyi uyumluluk sağlamak için, __VA_OPT__ tüm dil sürümlerinde belirteç tabanlı ön işlemci /Zc:preprocessor altında etkinleştirilir.

Örneğin, bu artık hatasız derlenmiş:

#define LOG_WRAPPER(message, ...) WRITE_LOG(__LINE__, message __VA_OPT__(, __VA_ARGS__))

// Failed to build under /std:c11, now succeeds.
LOG_WRAPPER("Log message");
LOG_WRAPPER("Log message with %s", "argument")

C23 dili

C23 için, /std:clatest derleyici anahtarı kullanılırken aşağıdakiler kullanılabilir:

typeof
typeof_unqual

Tüm C dil sürümleri için aşağıdakiler kullanılabilir:

__typeof__
__typeof_unqual__

C++ Standart Kitaplığı

C++23 özellikleri

Visual Studio 2022 sürüm 17.8'de uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.8, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

/FU hatayla karşılaşır

C derleyicisi, bir süredir yönetilen derlemeyi desteklemese bile /FU seçeneğini kabul ediyordu. Şimdi bir hatayla karşılaşır. Bu seçeneği geçen projelerin yalnızca C++/CLI projelerine kısıtlaması gerekir.

C++ Standart Kitaplığı

C++23'ün std ve std.compat adlı modülleri, /std:c++20 ile derlenirken artık kullanılabilir.

C++ Standart Kitaplığında yapılan değişikliklerin daha geniş bir özeti için bkz . STL Changelog VS 2022 17.8.

Visual Studio 2022 sürüm 17.7'de uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.7, Microsoft C/C++ derleyicisinde aşağıdaki vurgulanmış uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

C derleyicisine eklendi /std:clatest

Bu anahtar, C++ derleyicisi için /std:c++latest anahtarı gibi davranır. Anahtar, hem bir sonraki taslak C standardı için önerilen mevcut tüm derleyici ve standart kitaplık özelliklerini hem de bazı tamamlanmamış ve deneysel özellikleri etkinleştirir.

C++ Standart Kitaplığı

Kütüphane <print> artık destekleniyor. Bkz. P2093R14 Biçimlendirilmiş çıktı.

Uygulandı views::cartesian_product.

Standart Şablon Kitaplığı'na yapılan değişikliklerin daha geniş bir özeti için bkz . STL Changelog VS 2022 17.7.

using Uygunluk

Önceden, using yönergesi, kullanılmaması gereken durumlarda kullanılan ad alanlarından gelen adların görünür kalmasına neden olabiliyordu. Bu, using etkin bir yönergesi mevcut olmasa bile ad alanında bir ad bulmak için nitelenmemiş ad aramasına neden olabilir.

Yeni ve eski davranışa ilişkin bazı örnekler aşağıda verilmiştir.
Aşağıdaki açıklamalardaki "(1)" referansı, f<K>(t) ad alanındaki A çağrısı anlamına gelir.

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

Aynı temel sorun, daha önce derlenmiş kodun artık reddedilmesine neden olabilir:

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

Visual Studio 2022 sürüm 17.6'da uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.6, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Bileşik volatile atamalar artık kullanım dışı bırakılmıyor

C++20, volatile ile nitelendirilmiş türlere belirli işleçlerin uygulanmasını kullanım dışı bıraktı. Örneğin, aşağıdaki kod ile cl /std:c++20 /Wall test.cpp derlendiğinde:

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

Derleyici üretir test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20.

C++20'de bileşik atama işleçleri (formun @=işleçleri) kullanım dışı bırakıldı. C++23'te, C++20'de dışlanan bileşik işleçler artık kullanım dışı bırakılmaz. Örneğin, C++23'te aşağıdaki kod bir uyarı üretmezken C++20'de uyarı oluşturur:

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

Bu değişiklik hakkında daha fazla bilgi için bkz . CWG:2654

İfadelerde eşitliğin yeniden yazılması daha az bozulmaya neden olan bir değişikliktir (P2468R2)

C++20'de P2468R2 derleyiciyi aşağıdaki gibi kodu kabul etmek üzere değiştirdi:

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

Derleyici bu kodu kabul eder, bu da derleyicinin aşağıdaki gibi kodlarla daha katı olduğu anlamına gelir:

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

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

Derleyicinin 17.5 sürümü bu programı kabul eder. Derleyicinin 17.6 sürümü bunu reddeder. Belirsizliği gidermek için const öğesini operator== öğesine ekleyin. Veya aşağıdaki örnekte gösterildiği gibi tanıma karşılık gelen operator!= bir ekleyin:

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

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

Microsoft C/C++ derleyici sürümleri 17.5 ve 17.6, önceki programı kabul eder ve her iki sürümde de S::operator== çağırır.

P2468R2'da özetlenen genel programlama modeli, bir türe karşılık gelen bir operator!= varsa, genellikle yeniden yazma davranışını bastırmasıdır. Buna karşılık gelen operator!= ekleme, daha önce C++17'de derlenmiş kod için önerilen düzeltmedir. Daha fazla bilgi için bkz . Programlama Modeli.

Visual Studio 2022 sürüm 17.4'te uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.4, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Sabit türü olmayan kapsam dışı enum temel türleri

Visual Studio'nun Visual Studio 2022 sürüm 17.4'den önceki sürümlerinde, C++ derleyicisi sabit temel türü olmayan temel alınmamış bir numaralandırmanın temel türünü doğru şekilde belirlemedi. altında /Zc:enumTypesartık standart davranışı doğru şekilde uyguluyoruz.

C++ Standardı, bir enum'ın temel aldığı türün, o enum içindeki tüm numaralandırıcıları barındırabilecek kadar büyük olmasını gerektirir. Yeterince büyük numaralandırıcılar, alttaki türü enum'ün unsigned int, long long veya unsigned long long olarak ayarlayabilir. Daha önce, numaralandırıcı değerlerinden bağımsız olarak, böyle enum türleri Microsoft derleyicisinde her zaman int türüne sahipti.

Etkinleştirildiğinde, /Zc:enumTypes seçeneği potansiyel bir kaynak ve ikili uyumluluk bozulmasına neden olabilecek bir değişikliktir. Düzeltme ikili uyumluluğu etkileyebileceğinden varsayılan olarak kapalıdır ve tarafından /permissive-etkinleştirilmez. Uyumlu düzeltme etkinleştirildiğinde bazı numaralandırma türleri boyut değiştirir. Bazı Windows SDK üst bilgileri bu tür numaralandırma tanımlarını içerir.

Örnek

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

Sabit bir temel türü olmayan bir enum tanım içindeki numaralandırıcı türleri

Visual Studio'nun Visual Studio 2022 sürüm 17.4'den önceki sürümlerinde, C++ derleyicisi numaralandırıcı türlerini doğru modellemedi. Numaralandırmanın kapanış ayracına gelmeden önce, sabit bir temel türü olmayan numaralandırmalarda yanlış bir tür varsayılabilir. altında /Zc:enumTypes, derleyici artık standart davranışı doğru şekilde uygular.

C++ Standardı, sabit temel alınmamış bir numaralandırma tanımında başlatıcıların numaralandırıcı türlerini belirlediğini belirtir. Veya başlatıcısı olmayan numaralandırıcılar için, önceki numaralandırıcının türüne göre (taşmayı göz önünde bulundurarak). Daha önce, bu tür numaralandırıcılara her zaman temel alınan tür için bir yer tutucuyla (genellikle int) numaralandırmanın çıkarılmış türü verilirdi.

Etkinleştirildiğinde, /Zc:enumTypes seçeneği potansiyel bir kaynak ve ikili uyumluluk bozulmasına neden olabilecek bir değişikliktir. Düzeltme ikili uyumluluğu etkileyebileceğinden varsayılan olarak kapalıdır ve tarafından /permissive-etkinleştirilmez. Uyumlu düzeltme etkinleştirildiğinde bazı numaralandırma türleri boyut değiştirir. Bazı Windows SDK üst bilgileri bu tür numaralandırma tanımlarını içerir.

Örnek

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

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

Bu örnekte, numaralandırıcının A, numaralandırmanın kapanış ayracından önce char türünde olmalıdır, bu nedenle B, sizeof(char) kullanılarak başlatılmalıdır. Düzeltmeden /Zc:enumTypes önce, A hem çıkarılan bir temel tür ile bir numaralandırma türüne (Enum, int) sahipti ve B veya 4 kullanılarak sizeof(Enum) başlatıldı.

Visual Studio 2022 sürüm 17.3'te uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.3, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

C: İşaretçiler arasında geliştirilmiş değiştirici uyumluluk denetimi

C derleyicisi, özellikle void*işaretçiler arasındaki değiştiricileri düzgün karşılaştırmadı. Bu hata, const int** ve void* arasında uyumsuzluk, int* volatile* ve void* arasında ise uyumluluğun hatalı teşhisine yol açabilir.

Örnek

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
}

Visual Studio 2022 sürüm 17.2'de uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.2, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Tamamlanmamış çift yönlü karakter uyarıları

Visual Studio 2022 sürüm 17.2, açıklamalar ve dizelerdeki sonlandırılmamış Unicode çift yönlü karakterler için düzey 3 uyarısı C5255 ekler. Uyarı, Truva Atı Kaynağı: Nicholas Boucher ve Ross Anderson tarafından oluşturulan Görünmez Güvenlik Açıkları başlığı altında açıklanan güvenlik endişesini giderir. Unicode çift yönlü karakterler hakkında daha fazla bilgi için bkz . Unicode® Standart Ek #9: UNICODE ÇIFT YÖNLÜ ALGORITMA.

Uyarı C5255 yalnızca dönüştürmeden sonra Unicode çift yönlü karakterler içeren dosyaları ele alır. Bu uyarı UTF-8, UTF-16 ve UTF-32 dosyaları için geçerlidir, bu nedenle doğru kaynak kodlama sağlanmalıdır. Bu değişiklik kaynak uyumsuzluğuna neden olan bir değişikliktir.

Örnek (önce/sonra)

Visual Studio 2022 sürüm 17.2'den önceki Visual Studio sürümlerinde, tamamlanmamış bir çift yönlü karakter uyarı üretmiyordu. Visual Studio 2022 sürüm 17.2 uyarı C5255 üretir:

// 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 beraberlik bozucu

Visual Studio 2022 sürüm 17.2, tiebreaker kurallarında <charconv>from_chars()float yanlış sonuçlar üreten bir hatayı düzeltir. Bu hata, dar bir aralık içinde ardışık float değerlerin tam orta noktasında olan ondalık dizeleri etkiledi. (En küçük ve en büyük etkilenen değerler sırasıyla 32768.009765625 ve 131071.98828125'ydi.) Tiebreaker kuralı "çift"e yuvarlamak istedi ve "çift" "aşağı" anlamına geliyordu, ancak uygulama yanlışlıkla "yukarı" yuvarladı (double etkilenmedi). Daha fazla bilgi ve uygulama ayrıntıları için bkz. microsoft/STL#2366.

Bu değişiklik, belirtilen durum aralığındaki çalışma zamanı davranışını etkiler:

Örnek

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

Visual Studio 2022 sürüm 17.2'nin önceki sürümlerinde:

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.

Visual Studio 2022 sürüm 17.2 ve sonrasında:

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__, __STDC__’yi C için kullanılabilir hale getirir.

C standardı, uyumlu bir C uygulamasının __STDC__1 olarak tanımlamasını gerektirir. UCRT'nin, __STDC__1 olduğunda POSIX işlevlerini kullanıma sunmayan davranışı nedeniyle, bu makroyu C için varsayılan olarak tanımlamak, kararlı dil sürümlerinde hataya neden olan değişiklikler yapmadan mümkün değildir. Visual Studio 2022 sürüm 17.2 ve üzeri, bu makroları tanımlayan bir uyumluluk seçeneği /Zc:__STDC__ ekler. Seçeneğin olumsuz bir sürümü yoktur. Şu anda bu seçeneği C'nin gelecekteki sürümleri için varsayılan olarak kullanmayı planlıyoruz.

Bu değişiklik kaynak uyumsuzluğuna neden olan bir değişikliktir. C11 veya C17 modu etkinleştirildiğinde (/std:c11 veya /std:c17) ve /Zc:__STDC__ belirtildiğinde geçerlidir.

Örnek

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

*/

Eksik küme ayraçları için uyarı

Uyarı C5246, toplu başlatma sırasında bir alt nesnenin küme ayraçlarının eksik olduğunu bildirir. Visual Studio 2022 sürüm 17.2'den önce, uyarı anonim struct veya uniondurumunu işlemedi.

Bu değişiklik kaynak uyumsuzluğuna neden olan bir değişikliktir. Varsayılan olarak kapalı C5246 uyarısı etkinleştirildiğinde geçerlidir.

Örnek

Visual Studio 2022 sürüm 17.2 ve sonraki sürümlerinde bu kod artık bir hataya neden oluyor:

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

Bu sorunu çözmek için başlatıcıya küme ayraçları ekleyin.

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

Visual Studio 2022 sürüm 17.1'de uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.1, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Yerel olmayan lambda ifadeleri içinde hatalı biçimlendirilmiş yakalama varsayılanını algılama

C++ Standardı yalnızca blok kapsamındaki bir lambda ifadesinin yakalama varsayılanı olmasına izin verir. Visual Studio 2022 sürüm 17.1 ve sonraki sürümlerde derleyici, yerel olmayan bir lambda ifadesinde bir yakalama varsayılanına izin verilmediğini tespit eder. C5253 adlı yeni bir düzey 4 uyarısı yayar.

Bu değişiklik kaynak uyumsuzluğuna neden olan bir değişikliktir. Yeni lambda işlemcisini kullanan herhangi bir modda geçerlidir: /Zc:lambda, /std:c++20veya /std:c++latest.

Örnek

Visual Studio 2022 sürüm 17.1'de bu kod artık bir hata yayar:

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

Bu sorunu düzeltmek için yakalama varsayılanını kaldırın:

#pragma warning(error:5253)

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

C4028 artık işlevden işaretçiye işlemler için C4133'dür

Visual Studio 2022 sürüm 17.1'den önce, derleyici C kodundaki belirli işlev işaretçisi karşılaştırmalarında yanlış bir hata iletisi bildirdi. Aynı bağımsız değişken sayılarına ama uyumsuz türlere sahip iki işlev işaretçisini karşılaştırdığınızda yanlış ileti bildirildi. Şimdi işlev parametresi uyuşmazlığı yerine işaretçiden işleve uyumsuzluktan şikayet eden farklı bir uyarı yayınlıyoruz.

Bu değişiklik kaynak uyumsuzluğuna neden olan bir değişikliktir. Kod C olarak derlendiğinde uygulanır.

Örnek

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

Bağımsız olmayan bir unsurda hata static_assert

Visual Studio 2022'nin 17.1 ve sonraki sürümlerinde, static_assert ile ilişkili ifade bağımlı bir ifade değilse, derleyici ifadeyi ayrıştırıldığında değerlendirir. İfade false olarak değerlendirildiğinde, derleyici bir hata verir. Daha önce, static_assert bir işlev şablonunun gövdesindeyse (veya bir sınıf şablonunun üye işlevinin gövdesindeyse), derleyici bu analizi gerçekleştirmezdi.

Bu değişiklik kaynak uyumsuzluğuna neden olan bir değişikliktir. /permissive- veya /Zc:static_assert ima eden herhangi bir modda geçerlidir. Bu davranış değişikliği, derleyici seçeneği kullanılarak /Zc:static_assert- devre dışı bırakılabilir.

Örnek

Visual Studio 2022 sürüm 17.1 ve sonraki sürümlerinde bu kod artık bir hataya neden oluyor:

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

Bu sorunu düzeltmek için ifadeyi bağımlı hale getirin. Örneğin:

template<typename>
constexpr bool dependent_false = false;

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

Bu değişiklikle, derleyici yalnızca işlev şablonu f örneği oluşturulursa hata gösterir.

Visual Studio 2022 sürüm 17.0'da uyumluluk geliştirmeleri

Visual Studio 2022 sürüm 17.0, Microsoft C/C++ derleyicisinde aşağıdaki uyumluluk iyileştirmelerini, hata düzeltmelerini ve davranış değişikliklerini içerir.

Numaralandırma türü için bit alanı genişliği uyarısı

Bir sabit listesi türünün örneğini bit alanı olarak bildirdiğinizde, bit alanının genişliği numaralandırmanın tüm olası değerlerini barındırmalıdır. Aksi takdirde, derleyici bir tanılama iletisi verir. Şu örneği göz önünde bulundurun: Göz önünde bulundurun:

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

struct S {
  E e : 1;
};

Programcı, sınıf üyesinin S::e açıkça adlandırılmış enum değerlerden herhangi birini barındırabilmesini bekleyebilir. Numaralandırma öğelerinin sayısı göz önünde bulundurulduğunda, bu mümkün değildir. bit alanı, E'ün açıkça sağlanan değerlerinin aralığını (kavramsal olarak 'nin E) kaplayamaz. Bit alanı genişliğinin numaralandırmanın etki alanı için yeterince büyük olmadığı endişesini gidermek için MSVC'ye yeni bir (varsayılan olarak kapalı) uyarısı eklenir:

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

Bu derleyici davranışı, tüm /std ve /permissive modlarını etkileyen bir kaynak ve ikili uyumluluk kırıcı değişikliktir.

Sıralı işaretçi nullptr veya 0 ile karşılaştırmasında hata

C++ Standardı, bilmeden nullptr veya 0 ile sıralı bir işaretçi karşılaştırmasına izin verdi. Örneğin:

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

WG21 tarafından belge N3478 bu ihmali kaldırdı. Bu değişiklik MSVC'de uygulanır. Örnek /permissive- (ve /diagnostics:caret) kullanılarak derlendiğinde aşağıdaki hata oluşur:

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

Bu derleyici davranışı, tüm /permissive- modlarında /std kullanılarak derlenen kodu etkileyen bir kaynak ve ikili uyumsuzluk değişikliğidir.

Ayrıca bkz.

Microsoft C/C++ dil uyumluluğu