Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Microsoft C/C++ no Visual Studio (MSVC) faz melhorias de conformidade e correções de bugs em cada versão. Este artigo lista as melhorias significativas por versão principal e, em seguida, por versão. Para ir diretamente para as alterações de uma versão específica, use os links no topo deste artigo.
Este documento lista as alterações no Visual Studio 2022.
Para alterações em versões anteriores do Visual Studio:
Versão | Link de melhorias de conformidade |
---|---|
2019 | melhorias de conformidade com C++ no Visual Studio 2019 |
2017 | melhorias de conformidade com C++ no Visual Studio 2017 |
2003-2015 | Visual C++ O que há de novo de 2003 a 2015 |
Melhorias de conformidade no Visual Studio 2022 versão 17.14
O Visual Studio 2022 versão 17.14 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Melhorias de conformidade
- O fortalecimento da biblioteca padrão (P3471R4) transforma certas instâncias de comportamento indefinido na biblioteca padrão em uma chamada para __fastfail. Desativado por padrão. Defina
_MSVC_STL_HARDENING=1
em todo o projeto para ativar.
Comportamento melhorado
- Implementei "lápides destruidoras" para mitigar erros de uso após o livre. Desativado por padrão. Defina
_MSVC_STL_DESTRUCTOR_TOMBSTONES=1
em todo o projeto para ativar.
Correções de erros
Corrigidos erros errantes do compilador ao usar
<format>
em um projeto CUDA.Corrigido um problema do compilador em que o endereço de uma variável local podia "escapar" durante a avaliação de
constexpr
. Por exemplo: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
Exemplo #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 }
Código compilado com
/permissive-
não aceita mais uma combinação defriend
estatic
em uma declaração. A correção geralmente é removerstatic
da declaração. Por exemplo:struct S { friend static void f(); // Previously accepted, now emits error C2440: 'static' cannot be used with 'friend' };
Vinculação de referência a tipos qualificados voláteis fixados quando se referem a uma classe base ou derivada. Por exemplo:
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.
Para obter um resumo detalhado das alterações feitas na Biblioteca de Modelos Padrão, incluindo alterações de conformidade, correções de bugs e melhorias de desempenho, consulte STL Changelog VS 2022 17.14.
Melhorias de conformidade no Visual Studio 2022 versão 17.13
O Visual Studio 2022 versão 17.13 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Para obter um resumo detalhado das alterações feitas na Biblioteca de Modelos Padrão, incluindo alterações de conformidade, correções de bugs e melhorias de desempenho, consulte STL Changelog VS 2022 17.13.
Busca dependente de argumentos (ADL)
Construções de linguagem, como range-for e ligações estruturadas, têm regras especiais de pesquisa dependentes de argumentos para determinados identificadores, como begin
, end
ou get
. Anteriormente, essa pesquisa incluía candidatos do std
namespace, mesmo quando o namespace std
não faz parte do conjunto comum de namespaces associados para pesquisa dependente de argumento.
Os programas que introduziram declarações ao std
para essas construções deixam de compilar. Em vez disso, as declarações devem estar em um namespace associado normal para os tipos envolvidos (possivelmente incluindo o namespace global).
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>'
{
...
}
}
Não é possível modificar macros reservadas à implementação
Anteriormente, o compilador permitia alterar ou desdefinir certas macros fornecidas pela implementação, como _MSC_EXTENSIONS
. Alterar a definição de certas macros pode resultar em comportamento indefinido.
A tentativa de alterar ou desdefinir determinados nomes de macro reservados agora resulta no aviso de nível 1 C5308
. No modo /permissive-
, esse aviso é tratado como um erro.
#undef _MSC_EXTENSIONS // Warning C5308: Modifying reserved macro name `_MSC_EXTENSIONS` may cause undefined behavior
Melhorias de conformidade no Visual Studio 2022 versão 17.12
O Visual Studio 2022 versão 17.12 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Para obter um resumo detalhado das alterações feitas na Biblioteca de Modelos Padrão, incluindo alterações de conformidade, correções de bugs e melhorias de desempenho, consulte STL Changelog VS 2022 17.12.
_com_ptr_t::operator bool()
agora é explícito
Esta é uma alteração que quebra compatibilidade de origem/binária.
A conversão implícita para bool
de instâncias de _com_ptr_t
pode ser surpreendente ou levar a erros de compilação.
C.164: Evitar operadores de conversão implícitos nas Diretrizes Principais do C++ desencorajam funções de conversão implícitas. E _com_ptr_t
continha conversões implícitas para ambos bool
e Interface*
. Estas duas conversões implícitas podem levar a ambiguidades.
Para resolver isso, a conversão para bool
agora é explícita. A conversão para Interface*
permanece inalterada.
Uma macro é fornecida para desativar esse novo comportamento e restaurar a conversão implícita anterior. Compile com /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL
para optar por não receber esta alteração. Recomendamos que você modifique o código para não depender de conversões implícitas.
Por exemplo:
#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'
}
As expressões constantes já não são sempre noexcept
no modo permissivo
Esta é uma alteração que quebra compatibilidade de origem/binária.
Uma expressão constante era sempre noexcept
, mesmo que envolvesse uma chamada a uma função declarada com uma especificação de exceção que pode lançar. Este texto foi removido no C++17, embora o compilador do Microsoft Visual C++ ainda o suportasse no modo /permissive
em todas as versões de linguagem C++.
Esse comportamento de modo /permissive
é removido. As expressões constantes não recebem mais um comportamento implícito especial.
O especificador noexcept
em funções constexpr
é agora respeitado em todos os modos. Essa alteração é necessária para a implementação correta de resoluções de problemas principais posteriores que dependem do comportamento padrão noexcept
.
Por exemplo:
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.
}
Melhorias de conformidade no Visual Studio 2022 versão 17.11
O Visual Studio 2022 versão 17.11 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Para obter um resumo detalhado das alterações feitas na Biblioteca de Modelos Padrão, incluindo alterações de conformidade, correções de bugs e melhorias de desempenho, consulte STL Changelog VS 2022 17.11.
Imprimir linhas em branco com println
Por P3142R0, agora é fácil gerar uma linha em branco com println
. Este recurso está disponível ao compilar com /std:c++latest
.
Antes dessa mudança, você escreveu: println("");
Agora você escreve: println();
.
-
println();
equivale aprintln(stdout);
-
println(FILE* stream);
equivale aprintln(stream, "\n");
Implementado range_formatter
De acordo com P2286R8, range_formatter
está agora implementado. Este recurso está disponível ao compilar com /std:c++latest
.
Melhorias de conformidade no Visual Studio 2022 versão 17.10
O Visual Studio 2022 versão 17.10 inclui as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Para obter um resumo detalhado das alterações feitas na Biblioteca de Modelos Padrão, incluindo alterações de conformidade, correções de bugs e melhorias de desempenho, consulte STL Changelog VS 2022 17.10.
Especialização do operador de conversão com tipo de retorno explicitamente especificado
O compilador costumava especializar incorretamente os operadores de conversão em alguns casos, o que podia levar a um tipo de retorno incompatível. Essas especializações inválidas não acontecem mais. Esta é uma alteração que quebra o código-fonte.
// 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
}
Adicionado suporte para #elifdef
e #elifndef
Suporte adicionado para WG21 P2334R1 (C++23) e WG14 N2645 (C++23), que introduziu as diretivas de pré-processador #elifdef
e #elifndef
.
Requer /std:clatest
ou /std:c++latest
.
Antes:
#ifdef __cplusplus
#include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Depois:
#ifdef __cplusplus
#include <atomic>
#elifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Aplicação de _Alignas
num tipo estruturado em C
Aplica-se à linguagem C (C17 e posteriores). Também adicionado ao Microsoft Visual Studio 17.9
Em versões do Visual C++ anteriores ao Visual Studio 2022 versão 17.9, se o especificador de _Alignas
aparecesse ao lado de um tipo estruturado em uma declaração, ele não era aplicado corretamente de acordo com o ISO-C Standard.
// 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");
De acordo com o ISO-C Standard, este código deve ser compilado sem static_assert
emitir um diagnóstico.
A diretiva _Alignas
aplica-se apenas à variável membro member1
. Não deve alterar o alinhamento de struct Inner
. No entanto, antes do Visual Studio 17.9.1, o diagnóstico "alinhamento incorreto" era emitido. O compilador alinhou member2
a um deslocamento de 32 bytes dentro do tipo struct Outer
.
Esta é uma alteração de quebra binária, portanto, um aviso é emitido quando essa alteração entra em vigor. O aviso C5274 é agora emitido no nível de aviso 1 para o exemplo anterior: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects)
.
Além disso, em versões anteriores do Visual Studio, quando o especificador de _Alignas
aparecia ao lado de uma declaração de tipo anônimo, ele era ignorado.
// 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");
Anteriormente, ambas as instruções static_assert
falharam ao compilar esse código. Agora o código compila, mas emite os seguintes avisos de nível 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)
Para obter o comportamento anterior, substitua _Alignas(N)
por __declspec(align(N))
. Ao contrário _Alignas
, declspec(align)
se aplica ao tipo.
Aviso melhorado C4706
Esta é uma alteração que quebra o código-fonte. Anteriormente, o compilador não detetava a convenção de encapsular uma atribuição entre parênteses, se a atribuição fosse pretendida, para suprimir aviso C4706 sobre atribuição dentro de uma expressão condicional. O compilador agora deteta os parênteses e suprime o aviso.
#pragma warning(error: 4706)
struct S
{
auto mf()
{
if (value = 9)
return value + 4;
else
return value;
}
int value = 9;
};
O compilador agora também emite o aviso nos casos em que a função não é referenciada. Anteriormente, como mf
é uma função embutida que não é referenciada, o aviso C4706 não foi emitido para esse código. Agora o aviso é emitido:
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
Para corrigir esse aviso, use um operador de igualdade, value == 9
, se for isso que se pretendia. Ou, coloque a atribuição entre parênteses, (value = 9)
, se a atribuição for intencional. Caso contrário, uma vez que a função não é referenciada, remova-a.
Melhorias de conformidade no Visual Studio 2022 versão 17.9
O Visual Studio 2022 versão 17.9 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Para obter um resumo mais amplo das alterações feitas na Biblioteca de Modelos Padrão, consulte STL Changelog VS 2022 17.9.
Aplicação de _Alignas
num tipo estruturado em C
Em versões do Visual C++ anteriores ao Visual Studio 2022 versão 17.9, quando _Alignas
aparecia ao lado de um tipo de estrutura em uma declaração, ele não era aplicado corretamente de acordo com o ISO-C Standard. Por exemplo:
// 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");
De acordo com o ISO-C Standard, este código deve ser compilado sem que o static_assert
emita um diagnóstico. A diretiva _Alignas
aplica-se apenas à variável membro member1
. Não deve alterar o alinhamento de struct Inner
. No entanto, antes da versão 17.9.1 do Visual Studio, o diagnóstico "alinhamento incorreto" foi emitido. O compilador alinhou member2
a um deslocamento de 32 bytes dentro de struct Outer
.
Corrigir isso é uma alteração de quebra binária, então quando essa mudança de comportamento é aplicada um aviso é emitido. Para o código anterior, o Aviso C5274, "_Alignas
já não se aplica ao tipo 'Inner' (aplica-se apenas a objetos de dados declarados)", é agora emitido ao nível de aviso 1.
Em versões anteriores do Visual Studio, _Alignas
era ignorado quando aparecia ao lado de uma declaração de tipo anônimo. Por exemplo:
// 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");
Anteriormente, ambas as instruções static_assert
falharam ao compilar esse código. O código agora é compilado, mas com os seguintes avisos de nível 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)
Se você quiser o comportamento anterior, substitua _Alignas(N)
por __declspec(align(N))
. Ao contrário _Alignas
, declspec(align)
pode ser aplicado a um tipo.
__VA_OPT__
está habilitado como uma extensão em /Zc:preprocessor
__VA_OPT__
foi adicionado ao C++20 e C23. Antes de sua adição, não havia uma maneira padrão de elidir uma vírgula em uma macro variádica. Para proporcionar melhor compatibilidade retroativa, __VA_OPT__
é ativado pelo pré-processador baseado em token /Zc:preprocessor
em todas as versões de idioma.
Por exemplo, isso agora compila sem erro:
#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")
Língua C23
Para C23, o seguinte está disponível ao usar a opção de compilador /std:clatest
:
Estão disponíveis para todas as versões da linguagem C:
Biblioteca padrão C++
recursos do C++23
-
formattable
,range_format
,format_kind
eset_debug_format()
como parte de P2286R8 Intervalos de Formatação -
<mdspan>
por P0009R18 e alterações de redação subsequentes que foram aplicadas à Norma C++23. -
format()
ponteiros por P2510R3.
Melhorias de conformidade no Visual Studio 2022 versão 17.8
O Visual Studio 2022 versão 17.8 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
/FU
emite um erro
O compilador C costumava aceitar a opção /FU
, mesmo que não suporte a compilação gerenciada há algum tempo. Agora emite um erro. Os projetos que passam essa opção precisam restringi-la apenas a projetos C++/CLI.
Biblioteca padrão C++
Os módulos nomeados C++23 std
e std.compat
agora estão disponíveis ao compilar com /std:c++20
.
Para obter um resumo mais amplo das alterações feitas na Biblioteca Padrão C++, consulte STL Changelog VS 2022 17.8.
Melhorias de conformidade no Visual Studio 2022 versão 17.7
O Visual Studio 2022 versão 17.7 contém as seguintes melhorias de conformidade destacadas, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Adicionado /std:clatest
ao compilador C
Essa opção se comporta como a opção /std:c++latest
para o compilador C++. O switch permite todos os recursos de compilador e biblioteca padrão atualmente implementados propostos para o próximo projeto de padrão C, bem como alguns recursos experimentais e em andamento.
Biblioteca padrão C++
A biblioteca <print>
agora é suportada. Consulte P2093R14 Saída formatada.
Implementado views::cartesian_product
.
Para obter um resumo mais amplo das alterações feitas na Biblioteca de Modelos Padrão, consulte STL Changelog VS 2022 17.7.
using
conformidade
Anteriormente, a diretiva using
podia fazer com que nomes de namespaces usados permanecessem visíveis quando não deveriam. Isso pode fazer com que a pesquisa de nome não qualificada encontre um nome em um namespace, mesmo quando não há nenhuma diretiva using
ativa.
Aqui estão alguns exemplos do novo e do velho comportamento.
As referências nos comentários a seguir a "(1)" significam a chamada para f<K>(t)
no namespace A
:
namespace A
{
template<typename K, typename T>
auto f2(T t)
{
return f<K>(t); // (1) Unqualified lookup should not find anything
}
}
namespace B
{
template<typename K, typename T>
auto f(T t) noexcept
{ // Previous behavior: This function was erroneously found during unqualified lookup at (1)
return A::f2<K>(t);
}
}
namespace C
{
template<typename T>
struct S {};
template<typename, typename U>
U&& f(U&&) noexcept; // New behavior: ADL at (1) correctly finds this function
}
namespace D
{
using namespace B;
void h()
{
D::f<void>(C::S<int>());
}
}
O mesmo problema subjacente pode fazer com que o código compilado anteriormente seja rejeitado:
#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;
}
Melhorias de conformidade no Visual Studio 2022 versão 17.6
O Visual Studio 2022 versão 17.6 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
As atribuições de volatile
composto deixaram de ser obsoletas
C++20 tornou obsoleta a aplicação de certos operadores a tipos qualificados com volatile
. Por exemplo, quando o código a seguir é compilado com cl /std:c++20 /Wall test.cpp
:
void f(volatile int& expr)
{
++expr;
}
O compilador produz test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20
.
Em C++20, os operadores de atribuição compostos (operadores do formulário @=
) foram preteridos. No C++23, os operadores compostos excluídos no C++20 não são mais preteridos. Por exemplo, em C++23 o código a seguir não produz um aviso, enquanto em C++20:
void f(volatile int& e1, int e2)
{
e1 += e2;
}
Para obter mais informações sobre essa alteração, consulte CWG:2654
Reescrever a igualdade nas expressões é uma alteração menos disruptiva (P2468R2)
Em C++20, P2468R2 alterou o compilador para aceitar código como:
struct S
{
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} != S{};
O compilador aceita esse código, o que significa que o compilador é mais rigoroso com códigos como:
struct S
{
operator bool() const;
bool operator==(const S&);
};
bool b = S{} == S{};
A versão 17.5 do compilador aceita este programa. A versão 17.6 do compilador rejeita-o. Para corrigi-lo, adicione const
ao operator==
para remover a ambiguidade. Ou, adicione um operator!=
correspondente à definição, conforme mostrado no exemplo a seguir:
struct S
{
operator bool() const;
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} == S{};
Microsoft C/C++ compilador nas versões 17.5 e 17.6 aceitam o programa anterior e chamam S::operator==
em ambas as versões.
O modelo de programação geral descrito em P2468R2 é que, se houver um operator!=
correspondente para um tipo, ele normalmente suprime o comportamento de reescrita. Adicionar um operator!=
correspondente é a correção sugerida para o código compilado anteriormente em C++17. Para obter mais informações, consulte Programming Model.
Melhorias de conformidade no Visual Studio 2022 versão 17.4
O Visual Studio 2022 versão 17.4 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Tipos subjacentes de enum
não delimitados, sem tipo fixo
Em versões do Visual Studio anteriores ao Visual Studio 2022 versão 17.4, o compilador C++ não determinou corretamente o tipo subjacente de uma enumeração sem escopo sem nenhum tipo base fixo. Em /Zc:enumTypes
, agora implementamos corretamente o comportamento padrão.
O padrão C++ requer que o tipo subjacente de um enum
seja grande o suficiente para manter todos os enumeradores nesse enum
. Enumeradores suficientemente grandes podem definir o tipo subjacente do enum
como unsigned int
, long long
ou unsigned long long
. Anteriormente, esses tipos de enum
sempre tinham um tipo subjacente de int
no compilador da Microsoft, independentemente dos valores do enumerador.
Quando ativada, a opção /Zc:enumTypes
é uma fonte de alterações possíveis e de quebras binárias. Ele está desativado por padrão e não habilitado pelo /permissive-
, porque a correção pode afetar a compatibilidade binária. Alguns tipos de enumeração mudam de tamanho quando a correção conforme é habilitada. Certos cabeçalhos do SDK do Windows incluem essas definições de enumeração.
Exemplo
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
};
Tipos de enumeradores dentro de uma definição de enum
sem tipo subjacente fixo
Em versões do Visual Studio anteriores ao Visual Studio 2022 versão 17.4, o compilador C++ não modelou corretamente os tipos de enumeradores. Pode assumir um tipo incorreto em enumerações sem um tipo subjacente fixo antes do fecho da enumeração. Em /Zc:enumTypes
, o compilador agora implementa corretamente o comportamento padrão.
O padrão C++ especifica que, dentro de uma definição de enumeração de nenhum tipo subjacente fixo, os inicializadores determinam os tipos de enumeradores. Ou, para os enumeradores sem inicializador, pelo tipo do enumerador anterior (contabilizando sobrecarga). Anteriormente, esses enumeradores sempre recebiam o tipo deduzido da enumeração, com um espaço reservado para o tipo subjacente (normalmente int
).
Quando ativada, a opção /Zc:enumTypes
é uma fonte de alterações possíveis e de quebras binárias. Ele está desativado por padrão e não habilitado pelo /permissive-
, porque a correção pode afetar a compatibilidade binária. Alguns tipos de enumeração mudam de tamanho quando a correção conforme é habilitada. Certos cabeçalhos do SDK do Windows incluem essas definições de enumeração.
Exemplo
enum Enum {
A = 'A',
B = sizeof(A)
};
static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes
Neste exemplo, o enumerador A
deve ter o tipo char
antes da chave de fechamento da enumeração, portanto B
deve ser inicializado usando sizeof(char)
. Antes da correção /Zc:enumTypes
, A
tinha o tipo de enumeração Enum
com um tipo subjacente deduzido int
, e B
foi inicializado usando sizeof(Enum)
, ou 4.
Melhorias de conformidade no Visual Studio 2022 versão 17.3
O Visual Studio 2022 versão 17.3 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
C: Verificação de compatibilidade do modificador melhorada entre ponteiros
O compilador C não comparou corretamente os modificadores entre ponteiros, especialmente void*
. Este defeito pode resultar num diagnóstico inadequado de incompatibilidade entre const int**
e void*
e compatibilidade entre int* volatile*
e void*
.
Exemplo
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
}
Melhorias de conformidade no Visual Studio 2022 versão 17.2
O Visual Studio 2022 versão 17.2 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Avisos de caracteres bidirecionais não finalizados
O Visual Studio 2022 versão 17.2 adiciona aviso de nível 3 C5255 para caracteres bidirecionais Unicode não terminados em comentários e cadeias de caracteres. O aviso aborda uma preocupação de segurança descrita em Trojan Source: Invisible Vulnerabilities por Nicholas Boucher e Ross Anderson. Para obter mais informações sobre caracteres bidirecionais Unicode, consulte Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM.
Aviso C5255 só aborda arquivos que, após a conversão, contêm caracteres bidirecionais Unicode. Esse aviso se aplica a arquivos UTF-8, UTF-16 e UTF-32, portanto, a codificação de origem adequada deve ser fornecida. Esta alteração é uma alteração de quebra de fonte.
Exemplo (antes/depois)
Nas versões do Visual Studio anteriores ao Visual Studio 2022 versão 17.2, um caractere bidirecional não terminado não produzia um aviso. O Visual Studio 2022 versão 17.2 produz o aviso 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
desempate
O Visual Studio 2022 versão 17.2 corrige um bug nas regras de desempate <charconv>
from_chars()
float
que produzia resultados incorretos. Esse bug afetou cadeias decimais que estavam no ponto médio exato de valores de float
consecutivos, dentro de um intervalo estreito. (Os menores e maiores valores afetados foram 32768.009765625
e 131071.98828125
, respectivamente.) A regra de desempate queria arredondar para "par", e "par" por acaso significava "para baixo", mas a implementação arredondou incorretamente para "cima" (double
não foi afetado). Para obter mais informações e detalhes de implementação, consulte microsoft/STL#2366.
Essa alteração afeta o comportamento do tempo de execução no intervalo especificado de casos:
Exemplo
// 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");
}
Em versões anteriores ao Visual Studio 2022 versão 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.
No Visual Studio 2022 versão 17.2 e posteriores:
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__
disponibiliza __STDC__
para C
O padrão C requer que uma implementação C em conformidade defina __STDC__
como 1
. Devido ao comportamento do UCRT, que não expõe as funções POSIX quando __STDC__
é 1
, não é possível definir essa macro para C por padrão sem introduzir alterações significativas nas versões de idioma estável. O Visual Studio 2022 versão 17.2 e posterior adicionam uma opção de conformidade /Zc:__STDC__
que define essa macro. Não há nenhuma versão negativa da opção. Atualmente, planejamos usar essa opção por padrão para versões futuras do C.
Esta alteração é uma alteração de quebra de fonte. Aplica-se quando o modo C11 ou C17 está ativado (/std:c11
ou /std:c17
) e /Zc:__STDC__
é especificado.
Exemplo
// 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__
*/
Aviso de falta de chavetas
Aviso C5246 indica chavetas ausentes durante a inicialização agregada de um subobjeto. Antes do Visual Studio 2022 versão 17.2, o aviso não tratava do caso de um struct
anônimo ou union
.
Esta alteração é uma alteração de quebra de fonte. Aplica-se quando o aviso C5246, desativado por padrão, está ativado.
Exemplo
No Visual Studio 2022 versão 17.2 e posterior, esse código agora causa um erro:
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
*/
Para resolver este problema, acrescente chaves ao inicializador.
void f()
{
S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Melhorias de conformidade no Visual Studio 2022 versão 17.1
O Visual Studio 2022 versão 17.1 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Detetar padrão de captura mal formado em expressões lambda não locais
O C++ Standard só permite que uma expressão lambda no âmbito de um bloco tenha um capture-default. No Visual Studio 2022 versão 17.1 e posterior, o compilador deteta quando um padrão de captura não é permitido em uma expressão lambda não local. Emite um novo aviso de nível 4, C5253.
Esta alteração é uma alteração de quebra de fonte. Ele se aplica em qualquer modo que use o novo processador lambda: /Zc:lambda
, /std:c++20
ou /std:c++latest
.
Exemplo
No Visual Studio 2022 versão 17.1, esse código agora emite um erro:
#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; };
// ^
Para corrigir esse problema, remova o padrão de captura:
#pragma warning(error:5253)
auto incr = [](int value) { return value + 1; };
C4028 agora é C4133 para operações de conversão de função para ponteiro
Antes do Visual Studio 2022 versão 17.1, o compilador reportava uma mensagem de erro incorreta em certas comparações de ponteiros para funções no código C. A mensagem incorreta foi apresentada quando se compararam dois ponteiros de função que tinham o mesmo número de argumentos, mas tipos incompatíveis. Agora, emitimos um aviso diferente que indica incompatibilidade de ponteiro para função, em vez de incompatibilidade de parâmetros de função.
Esta alteração é uma alteração de quebra de fonte. Aplica-se quando o código é compilado como C.
Exemplo
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)'
Erro em um static_assert
não dependente
No Visual Studio 2022 versão 17.1 e posterior, se a expressão associada a um static_assert
não for uma expressão dependente, o compilador avaliará a expressão quando ela for analisada. Se a expressão for avaliada como false
, o compilador emitirá um erro. Anteriormente, se o static_assert
estivesse dentro do corpo de um modelo de função (ou dentro do corpo de uma função membro de um modelo de classe), o compilador não executaria essa análise.
Esta alteração é uma alteração de quebra de fonte. Aplica-se em qualquer modalidade que implique /permissive-
ou /Zc:static_assert
. Essa alteração no comportamento pode ser desabilitada usando a opção /Zc:static_assert-
compilador.
Exemplo
No Visual Studio 2022 versão 17.1 e posterior, esse código agora causa um erro:
template<typename T>
void f()
{
static_assert(false, "BOOM!");
}
Para corrigir esse problema, torne a expressão dependente. Por exemplo:
template<typename>
constexpr bool dependent_false = false;
template<typename T>
void f()
{
static_assert(dependent_false<T>, "BOOM!");
}
Com essa alteração, o compilador só emite um erro se o modelo de função f
for instanciado.
Melhorias de conformidade no Visual Studio 2022 versão 17.0
O Visual Studio 2022 versão 17.0 contém as seguintes melhorias de conformidade, correções de bugs e alterações de comportamento no compilador Microsoft C/C++.
Aviso sobre a largura do campo de bits para o tipo de enumeração
Quando você declara uma instância de um tipo de enumeração como um campo de bits, a largura do campo de bits deve acomodar todos os valores possíveis da enumeração. Caso contrário, o compilador emite uma mensagem de diagnóstico. Considere este exemplo: Considere:
enum class E : unsigned { Zero, One, Two };
struct S {
E e : 1;
};
Um programador pode esperar que o membro da classe S::e
possa manter qualquer um dos valores enum
explicitamente nomeados. Dado o número de elementos de enumeração, não é possível. O campo de bits não pode cobrir o intervalo de valores explicitamente fornecidos de E
(conceitualmente, o domínio de E
). Para resolver a preocupação de que a largura do campo de bits não é grande o suficiente para o domínio da enumeração, um novo aviso (desativado por padrão) é adicionado ao 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 };
^
Esse comportamento do compilador é uma alteração de quebra binária e de origem que afeta todos os modos /std
e /permissive
.
Erro na comparação ordenada do ponteiro com nullptr
ou 0
O padrão C++ inadvertidamente permitiu uma comparação ordenada de ponteiro contra nullptr
ou 0. Por exemplo:
bool f(int *p)
{
return p >= 0;
}
O documento WG21 N3478 removeu essa supervisão. Esta alteração é implementada no MSVC. Quando o exemplo é compilado usando /permissive-
(e /diagnostics:caret
), ele emite o seguinte erro:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
return p >= 0;
^
Este comportamento do compilador é uma alteração que quebra a compatibilidade de origem e binária, afetando o código compilado usando /permissive-
em todos os modos /std
.