Aprimoramentos de conformidade do C++, alterações de comportamento e correções de bugs no Visual Studio 2022
O Microsoft C/C++ no Visual Studio (MSVC) faz aprimoramentos de conformidade e correções de bugs em cada versão. Este artigo lista as melhorias significativas por versão principal e depois pela versão. Para ir diretamente para as alterações de uma versão específica, use os links Neste artigo na parte superior 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 o C++ no Visual Studio 2019 |
2017 | Aprimoramentos de conformidade do C++ no Visual Studio 2017 |
2003-2015 | O que há de novo no Visual C++ de 2003 até 2015 |
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 do 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 interruptiva de origem/binário.
A conversão implícita para bool
instâncias from pode ser surpreendente ou levar a erros do _com_ptr_t
compilador. As funções de conversão implícitas são desencorajadas pelas Diretrizes Principais do C++ (C.164) e _com_ptr_t
continham conversões implícitas para ambos e bool
Interface*
. Essas duas conversões implícitas podem levar a ambiguidades.
Para ajudar a resolver isso, a conversão para bool
agora é explícita. A conversão para Interface*
permanece inalterada.
Uma macro é fornecida para recusar esse novo comportamento e restaurar a conversão implícita anterior. Compile com /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL
para recusar essa 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 não estão mais sempre noexcept
no modo permissivo
Esta é uma alteração interruptiva de origem/binário.
Uma expressão constante sempre foi noexcept
, mesmo que envolvesse uma chamada de função para uma função declarada com uma especificação de exceção potencialmente lançada. Esse texto foi removido no C++17, embora o compilador do Microsoft Visual C++ ainda o suportasse no /permissive
modo em todas as versões da linguagem C++.
Esse /permissive
comportamento de modo é removido. As expressões constantes não recebem mais um comportamento implícito especial.
O noexcept
especificador nas constexpr
funções 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 do 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.
Imprima linhas em branco com println
Por P3142R0, agora é fácil gerar uma linha em branco com println
. Esse recurso está disponível ao compilar com /std:c++latest
o .
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
Por P2286R8, range_formatter
agora está implementado. Esse recurso está disponível ao compilar com /std:c++latest
o .
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 do Microsoft C/C++.
Para um resumo detalhado das alterações feitas na Biblioteca de Modelos Standard, incluindo mudanças de conformidade, correções de bug e melhorias de desempenho, consulte Log de Alterações da STL VS 2022 17.10.
Especialização do operador de conversão com tipo de retorno explicitamente especificado
O compilador costumava especializar operadores de conversão incorretamente em alguns casos, o que poderia levar a um tipo de retorno incompatível. Essas especializações inválidas não ocorrem mais. Essa é uma alteração interruptiva do 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 introduziram as diretivas de pré-processamento #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
em um tipo estruturado em C
Aplica-se à linguagem C (C17 e posteriores). Também adicionado ao Microsoft Visual Studio 17.9
Nas versões do Visual C++ anteriores ao Visual Studio 2022 versão 17.9, se o especificador _Alignas
aparecesse adjacente a 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, esse código deve ser compilado sem que static_assert
emita um diagnóstico.
A diretiva _Alignas
aplica-se somente à variável membro member1
. Ela não deve alterar o alinhamento de struct Inner
. Entretanto, antes do Visual Studio 17.9.1, o diagnóstico "alinhamento incorreto" era emitido. O compilador alinhava member2
a um deslocamento de 32 bytes dentro do tipo struct Outer
.
Essa é uma alteração interruptiva binária, portanto, um aviso agora é 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, nas versões anteriores do Visual Studio, quando o especificador _Alignas
aparecia adjacente a 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 declarações static_assert
falhavam ao compilar esse código. Agora o código é compilado, 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 de _Alignas
, declspec(align)
se aplica ao tipo.
Aviso aprimorado C4706
Essa é uma alteração interruptiva do código-fonte. Anteriormente, o compilador não detectava a convenção de encapsulamento de uma atribuição entre parênteses, se a atribuição fosse intencional, para suprimir o aviso C4706 sobre atribuição em uma expressão condicional. Agora, o compilador detecta 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 era 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 essa for a intenção. Ou, envolva a atribuição entre parênteses, (value = 9)
, se for essa a intenção. Caso contrário, como 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 erros e alterações de comportamento no compilador do Microsoft C/C++.
Para obter um resumo mais amplo das alterações feitas na Biblioteca de Modelos Standard, consulte STL Changelog VS 2022 17.9.
Aplicação de _Alignas
em um tipo estruturado em C
Nas 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, esse código deveria ser compilado sem que o static_assert
emitisse um diagnóstico. A diretiva _Alignas
aplica-se somente à variável membro member1
. Ela 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" era emitido. O compilador alinhava member2
a um deslocamento de 32 bytes dentro de struct Outer
.
Corrigir isso é uma alteração interruptiva binária, portanto, quando essa alteração de comportamento é aplicada, um aviso é emitido. Para o código anterior, o aviso C5274, "_Alignas
não se aplica mais ao tipo 'Inner' (aplica-se somente a objetos de dados declarados)" é agora emitido no 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 declarações static_assert
falhavam 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 de _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 ao C23. Antes de sua adição, não havia uma maneira padrão de omitir uma vírgula em um macro variádico. Para melhorar a compatibilidade com versões anteriores, __VA_OPT__
está habilitado no pré-processador baseado em token /Zc:preprocessor
em todas as versões da linguagem.
Por exemplo, isso agora compila sem erros:
#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")
Linguagem C23
Para C23, os seguintes recursos estão disponíveis ao usar a alternância do compilador /std:clatest
:
O seguinte está disponível para todas as versões da linguagem C:
Biblioteca Padrão do C++
Características do C++23
formattable
,range_format
,format_kind
eset_debug_format()
como parte de Intervalos de Formatação P2286R8<mdspan>
de acordo com P0009R18 e alterações de redação subsequentes que foram aplicadas ao C++23 Standard.format()
ponteiros de acordo com 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 bug e alterações de comportamento no compilador do Microsoft C/C++.
/FU
emite um erro
O compilador C costumava aceitar a opção /FU
, embora não tenha suporte para compilação gerenciada há algum tempo. Agora, ele emite um erro. Os projetos que passam essa opção precisam restringi-la somente 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++, confira 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 os seguintes aprimoramentos de conformidade realçados, correções de bug e alterações de comportamento no compilador do Microsoft C/C++.
Adicionado /std:clatest
ao compilador C
Essa opção se comporta como a alternância /std:c++latest
do compilador C++. A alternância habilita todos os recursos do compilador e da biblioteca padrão atualmente implementados propostos para o próximo rascunho do padrão C, assim como alguns recursos experimentais e em andamento.
Biblioteca Padrão C++
Agora há suporte para a biblioteca <print>
. Confira Saída formatada P2093R14.
views::cartesian_product
implementado.
Para obter um resumo mais amplo das alterações feitas na Biblioteca de Modelos Padrão, confira STL Changelog VS 2022 17.7.
Conformidade using
Anteriormente, a diretiva using
poderia fazer com que os nomes de namespaces usados permanecessem visíveis quando não deveriam. Isso pode fazer com que a pesquisa de nome não qualificada localize um nome em um namespace mesmo quando não houver nenhuma diretiva using
ativa.
Aqui estão alguns exemplos do comportamento novo e antigo.
Referências nos seguintes comentários para "(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;
}
Aprimoramentos de conformidade no Visual Studio 2022 versão 17.6
O Visual Studio 2022 versão 17.6 apresenta os aprimoramentos de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.
Atribuições volatile
compostas não foram mais preteridas
C++20 preterido aplicando determinados operadores a tipos qualificados com volatile
. Por exemplo, quando o seguinte código é 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
.
No C++20, os operadores de atribuição composta (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, no C++23, o código a seguir não produz um aviso, enquanto no C++20:
void f(volatile int& e1, int e2)
{
e1 += e2;
}
Para obter mais informações sobre essa alteração, confira CWG:2654
Reescrever a igualdade em expressões consiste menos em uma alteração interruptiva (P2468R2)
No 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 estrito com código 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 o rejeita. Para corrigi-lo, adicione const
a operator==
para remover a ambiguidade. Ou adicione um correspondente operator!=
à 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{};
As versões 17.5 e 17.6 do compilador do Microsoft C/C++ aceitam o programa anterior e chamadas S::operator==
em ambas as versões.
O modelo de programação geral descrito em P2468R2 é que, se há um correspondente operator!=
para um tipo, ele normalmente suprime o comportamento de reescrita. Adicionar um correspondente operator!=
é a correção sugerida para o código que foi compilado anteriormente no C++17. Para saber mais, confira Modelo de programação.
Aprimoramentos de conformidade no Visual Studio 2022 versão 17.4
O Visual Studio 2022 versão 17.4 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.
Tipos subjacentes de enum
sem escopo sem tipo fixo
Em versões do Visual Studio antes do Visual Studio 2022 versão 17.4, o compilador C++ não determinava corretamente o tipo subjacente de uma enumeração sem escopo sem tipo base fixo. No /Zc:enumTypes
, agora implementamos corretamente o comportamento padrão.
O C++ Standard 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 enum
sempre tinham um tipo subjacente de int
no compilador da Microsoft, independentemente dos valores do enumerador.
Quando habilitada, a opção /Zc:enumTypes
é uma possível alteração de falha de origem e binária. Ela está desativada por padrão e não está habilitada por /permissive-
porque a correção pode afetar a compatibilidade binária. Alguns tipos de enumeração mudam de tamanho quando a correção de conformidade está habilitada. Determinados 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 enum
sem tipo subjacente fixo
Nas versões do Visual Studio antes do Visual Studio 2022 versão 17.4, o compilador C++ não modelava corretamente os tipos de enumeradores. Ele poderia assumir um tipo incorreto em enumerações sem um tipo subjacente fixo antes da chave de fechamento da enumeração. No /Zc:enumTypes
, o compilador agora implementa corretamente o comportamento padrão.
O C++ Standard especifica que, dentro de uma definição de enumeração sem tipo subjacente fixo, os inicializadores determinam os tipos de enumeradores. Ou, para os enumeradores sem inicializador, pelo tipo do enumerador anterior (contabilizando o estouro). Anteriormente, esses enumeradores sempre recebiam o tipo deduzido da enumeração, com um espaço reservado para o tipo subjacente (normalmente int
).
Quando habilitada, a opção /Zc:enumTypes
é uma possível alteração de falha de origem e binária. Ela está desativada por padrão e não está habilitada por /permissive-
porque a correção pode afetar a compatibilidade binária. Alguns tipos de enumeração mudam de tamanho quando a correção de conformidade está habilitada. Determinados 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, então B
deve ser inicializado usando sizeof(char)
. Antes da correção /Zc:enumTypes
, A
tinha um tipo de enumeração Enum
com um tipo subjacente deduzido int
e B
era inicializado usando sizeof(Enum)
ou 4.
Aprimoramentos de conformidade no Visual Studio 2022 versão 17.3
O Visual Studio 2022 versão 17.3 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.
C: Verificação de compatibilidade aprimorada do modificador entre ponteiros
O compilador C não comparou corretamente os modificadores entre ponteiros, especialmente void*
. Esse defeito pode resultar em um 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
}
Aprimoramentos de conformidade no Visual Studio 2022 versão 17.2
O Visual Studio 2022 versão 17.2 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.
Avisos de caracteres bidirecionais não finalizados
O Visual Studio 2022 versão 17.2 adiciona o aviso de nível 3 C5255 para caracteres bidirecionais Unicode não finalizados 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, confira Unicode® Standard Annex #9: UNICODE BIDIRECTIONAL ALGORITHM.
O aviso C5255 apenas aborda arquivos que, após a conversão, contêm caracteres bidirecionais Unicode. Esse aviso se aplica aos arquivos UTF-8, UTF-16 e UTF-32, portanto, a codificação de origem adequada deve ser fornecida. Essa alteração é uma alteração interruptiva do código.
Exemplo (antes/depois)
Nas versões do Visual Studio antes do Visual Studio 2022 versão 17.2, um caractere bidirecional não finalizado 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 em <charconv>
from_chars()
float
regras de desempate que produziam resultados incorretos. Esse bug afetava cadeias de caracteres decimais que estavam no ponto médio exato de valores consecutivos float
, 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" passou a ser "para baixo", mas a implementação arredondou incorretamente "para cima" (double
não foi afetada). Para obter mais informações e detalhes de implementação, consulte microsoft/STL#2366.
Essa alteração afeta o comportamento do runtime no intervalo de casos especificado:
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 do C requer que uma implementação do 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 o C por padrão sem introduzir alterações interruptivas nas versões estáveis da linguagem. O Visual Studio 2022 versão 17.2 e posteriores adiciona uma opção de conformidade /Zc:__STDC__
que define essa macro. Não há uma versão negativa da opção. Atualmente, planejamos usar essa opção por padrão para versões futuras do C.
Essa alteração é uma alteração interruptiva do código. Ela se aplica quando o modo C11 ou C17 está habilitado (/std:c11
ou /std:c17
) e /Zc:__STDC__
está 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 para chaves ausentes
O aviso C5246 relata chaves ausentes durante a inicialização agregada de um subobjeto. Antes do Visual Studio 2022 versão 17.2, o aviso não lidava com o caso de um struct
ou union
anônimo.
Essa alteração é uma alteração interruptiva do código. Ela se aplica quando o aviso C5246, desativado por padrão, é habilitado.
Exemplo
No Visual Studio 2022 versão 17.2 e posteriores, 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 esse problema, adicione chaves ao inicializador:
void f()
{
S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Aprimoramentos de conformidade no Visual Studio 2022 versão 17.1
O Visual Studio 2022 versão 17.1 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.
Detectar padrão de captura mal formada em expressões lambda não locais
O Padrão do C++ só permite que uma expressão lambda no escopo de bloco tenha um padrão de captura. No Visual Studio 2022 versão 17.1 e posteriores, o compilador detecta quando um padrão de captura não é permitido em uma expressão lambda não local. Ele emite um novo aviso de nível 4, C5253.
Essa alteração é uma alteração interruptiva do código. Ela se aplica a 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; };
O C4028 agora é C4133 para operações de função a ponteiro
Antes do Visual Studio 2022 versão 17.1, o compilador relatava uma mensagem de erro incorreta em determinadas comparações de ponteiro para função no código do C. A mensagem incorreta era relatada quando você comparava dois ponteiros de função que tinham as mesmas contagens de argumentos, mas tipos incompatíveis. Agora, emitimos um aviso diferente que informa da incompatibilidade do ponteiro para a função em vez da incompatibilidade do parâmetro da função.
Essa alteração é uma alteração interruptiva do código. 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 posteriores, se a expressão associada a um static_assert
não for uma expressão dependente, o compilador avalia a expressão quando ela é analisada. Se a expressão for avaliada como false
, o compilador emitirá um erro. Anteriormente, se a 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.
Essa alteração é uma alteração interruptiva do código. Ela se aplica a qualquer modo que implique /permissive-
ou /Zc:static_assert
. Essa alteração no comportamento pode ser desabilitada usando a opção do compilador /Zc:static_assert-
.
Exemplo
No Visual Studio 2022 versão 17.1 e posteriores, 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ó emitirá um erro se o modelo de função f
for instanciado.
Aprimoramentos de conformidade no Visual Studio 2022 versão 17.0
O Visual Studio 2022 versão 17.0 apresenta as melhorias de conformidade, correções de bug e alterações de comportamento a seguir no compilador do Microsoft C/C++.
Aviso na largura do campo de bits para o tipo 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 emitirá 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 conter qualquer um dos valores explicitamente nomeados enum
. Dado o número de elementos de enumeração, isso não é possível. O campo de bits não pode cobrir o intervalo de valores fornecidos explicitamente de E
(conceitualmente, o domínio de E
). Para resolver a questã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) foi 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 interruptiva de código e binário que afeta os modos /std
e /permissive
.
Erro na comparação ordenada de ponteiro em relação a nullptr
ou 0
O Padrão do C++ inadvertidamente permitia uma comparação de ponteiro ordenada em relação a nullptr
ou 0. Por exemplo:
bool f(int *p)
{
return p >= 0;
}
O trabalho N3478 do WG21 removeu essa omissão. Essa 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;
^
Esse comportamento do compilador é uma alteração de falha de código e binária que afeta o código compilado usando /permissive-
em todos os modos /std
.