Mejoras en la conformidad de C++, cambios de comportamiento y correcciones de errores en Visual Studio 2022
Microsoft C/C++ en Visual Studio (MSVC) hace mejoras de conformidad y corrige errores en cada versión. En este artículo se enumeran las mejoras notables por versión principal y luego por versión. Para saltar directamente a los cambios de una versión específica, use los vínculos En este artículo.
En este documento se enumeran los cambios en Visual Studio 2022.
Para obtener los cambios en Visual Studio 2019, vea Mejoras de conformidad de C++ en Visual Studio 2019.
Para conocer los cambios en Visual Studio 2017, consulte Mejoras de conformidad de C++ en Visual Studio 2017.
Para obtener los cambios en versiones anteriores, vea Novedades de Visual C++ 2003 a 2015.
Mejoras de conformidad en Visual Studio 2022, versión 17.11
Visual Studio 2022, versión 17.11, tiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento en el compilador de Microsoft C/C++.
Para obtener un resumen detallado de los cambios realizados en la biblioteca de plantillas estándar, incluidos los cambios de conformidad, las correcciones de errores y las mejoras de rendimiento, consulte STL Changelog VS 2022 17.11.
Imprimir líneas en blanco con println
Por P3142R0, ahora es fácil generar una línea en blanco con println
. Esta característica está disponible al compilar con /std:c++latest
.
Antes de este cambio, escribió: println("");
Ahora escribe: println();
.
println();
es equivalente aprintln(stdout);
println(FILE* stream);
es equivalente aprintln(stream, "\n");
Implementado range_formatter
Por P2286R8, range_formatter
ahora se implementa. Esta característica está disponible al compilar con /std:c++latest
.
Mejoras de cumplimiento en Visual Studio 2022, versión 17.10
Visual Studio 2022, versión 17.10 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Para obtener un resumen detallado de los cambios realizados en la biblioteca de plantillas estándar, incluidos los cambios de conformidad, las correcciones de errores y las mejoras de rendimiento, vea Registro de cambios de STL en VS 2022 17.10.
Especialización del operador de conversión con el tipo de valor devuelto especificado explícitamente
El compilador usado para la especialización incorrecta de los operadores de conversión en algunos casos podría provocar un tipo de valor devuelto no coincidente. Estas especializaciones no válidas ya no se producen. Es un cambio importante del código fuente.
// 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
}
Compatibilidad agregada con #elifdef
y #elifndef
Se ha agregado compatibilidad con WG21 P2334R1 (C++23) y WG14 N2645 (C++23), donde se introducían las directivas de preprocesador #elifdef
y #elifndef
.
Se necesita /std:clatest
o /std:c++latest
.
Antes:
#ifdef __cplusplus
#include <atomic>
#elif !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Después:
#ifdef __cplusplus
#include <atomic>
#elifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#else
#include <custom_atomics_library.h>
#endif
Aplicación de _Alignas
en un tipo estructurado en C
Se aplica al lenguaje C (C17 y versiones posteriores). También se ha agregado a Microsoft Visual Studio 17.9
En versiones de Visual C++ anteriores a la versión 17.9 de Visual Studio 2022, si el especificador _Alignas
aparecía junto a un tipo estructurado en una declaración, no se aplicaba correctamente según el estándar ISO-C.
// compile with /std:c17
#include <stddef.h>
struct Outer
{
_Alignas(32) struct Inner { int i; } member1;
struct Inner member2;
};
static_assert(offsetof(struct Outer, member2)==4, "incorrect alignment");
Según el estándar ISO-C, este código se debe compilar sin que static_assert
emita un diagnóstico.
La directiva _Alignas
solo se aplica a la variable miembro member1
. No debe cambiar la alineación de struct Inner
. Pero antes de Visual Studio 17.9.1, se emitía el diagnóstico "alineación incorrecta". El compilador alineaba member2
a un desplazamiento de 32 bytes dentro del tipo struct Outer
.
Se trata de un cambio importante binario, por lo que ahora se emite una advertencia cuando este cambio surte efecto. Ahora la advertencia C5274 se emite en el nivel de advertencia 1 para el ejemplo anterior: warning C5274: behavior change: _Alignas no longer applies to the type 'Inner' (only applies to declared data objects)
.
Además, en versiones anteriores de Visual Studio, cuando el especificador _Alignas
aparecía junto a una declaración de tipo anónimo, se omitía.
// 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, se producía un error en las dos instrucciones static_assert
al compilar este código. Ahora el código se compila, pero emite las siguientes advertencias de nivel 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 obtener el comportamiento anterior, reemplace _Alignas(N)
por __declspec(align(N))
. A diferencia de _Alignas
, declspec(align)
se aplica al tipo.
Advertencia C4706 mejorada
Es un cambio importante del código fuente. Anteriormente, el compilador no detectaba la convención de encapsular una asignación entre paréntesis, si la asignación estaba prevista, para suprimir la advertencia C4706 sobre la asignación dentro de una expresión condicional. Ahora, el compilador detecta los paréntesis y suprime la advertencia.
#pragma warning(error: 4706)
struct S
{
auto mf()
{
if (value = 9)
return value + 4;
else
return value;
}
int value = 9;
};
El compilador ahora también emite la advertencia en los casos en los que no se hace referencia a la función. Anteriormente, como mf
es una función insertada a la que no se hace referencia, no se emitía la advertencia C4706 para este código. Ahora se emite la advertencia:
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 corregir esta advertencia, use un operador de igualdad, value == 9
, si es lo que se pretendía. O bien, encapsule la asignación entre paréntesis, (value = 9)
, si la asignación era lo previsto. De lo contrario, como no se hace referencia a la función, quítela.
Mejoras de cumplimiento en Visual Studio 2022, versión 17.9
Visual Studio 2022, versión 17.9 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Para obtener un resumen más amplio de los cambios realizados en la biblioteca de plantillas estándar, vea Registro de cambios de STL en VS 2022 17.9.
Aplicación de _Alignas
en un tipo estructurado en C
En versiones de Visual C++ anteriores a la versión 17.9 de Visual Studio 2022, si el especificador _Alignas
aparecía junto a un tipo estructurado en una declaración, no se aplicaba correctamente según el estándar ISO-C. Por ejemplo:
// 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");
Según el estándar ISO-C, este código se debe compilar sin que static_assert
emita un diagnóstico. La directiva _Alignas
solo se aplica a la variable miembro member1
. No debe cambiar la alineación de struct Inner
. Pero antes de la versión 17.9.1 de Visual Studio, se emitía el diagnóstico "alineación incorrecta". El compilador alineaba member2
a un desplazamiento de 32 bytes dentro de struct Outer
.
Esta corrección es un cambio importante binario, por lo que al aplicar este cambio en el comportamiento se emite una advertencia. En el código anterior, la advertencia C5274, "_Alignas
ya no se aplica al tipo "Inner" (solo se aplica a objetos de datos declarados)" ahora se emite en el nivel de advertencia 1.
En versiones anteriores de Visual Studio, se omitía _Alignas
cuando aparecía junto a una declaración de tipo anónimo. Por ejemplo:
// 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, se producía un error en las dos instrucciones static_assert
al compilar este código. Ahora el código se compila, pero con las siguientes advertencias de nivel 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)
Si quiere el comportamiento anterior, reemplace _Alignas(N)
por __declspec(align(N))
. A diferencia de _Alignas
, declspec(align)
se puede aplicar a un tipo.
__VA_OPT__
se habilita como una extensión en /Zc:preprocessor
__VA_OPT__
se ha agregado a C++20 y C23. Antes de su adición, no había una manera estándar de omitir una coma en una macro variádica. A fin de proporcionar una mejor compatibilidad con versiones anteriores, __VA_OPT__
se habilita en el preprocesador basado en tokens /Zc:preprocessor
en todas las versiones de lenguaje.
Por ejemplo, ahora esto se compila sin errores:
#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")
Lenguaje C23
Para C23, se dispone de lo siguiente al usar el modificador del compilador /std:clatest
:
Lo siguiente está disponible para todas las versiones del lenguaje C:
Biblioteca estándar de C++
Características de C++23
formattable
,range_format
,format_kind
yset_debug_format()
como parte de los intervalos de formato de P2286R8<mdspan>
según P0009R18 y los cambios de redacción posteriores que se aplicaron al estándar de C++23.- Punteros
format()
según P2510R3.
Mejoras de cumplimiento en Visual Studio 2022, versión 17.8
Visual Studio 2022, versión 17.8 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
/FU
emite un error
El compilador C usado para aceptar la opción/FU
, aunque no admita la compilación administrada durante algún tiempo. Ahora emite un error. Los proyectos que pasan esta opción solo deben restringirlo a proyectos de C++/CLI.
Biblioteca estándar de C++
Los módulos con nombre C++23 std
y std.compat
ahora están disponibles al compilar con /std:c++20
.
Para obtener un resumen más amplio de los cambios realizados en la biblioteca Estándar de C++, consulte STL Changelog VS 2022 17.8.
Mejoras de cumplimiento en Visual Studio 2022, versión 17.7
Visual Studio 2022, versión 17.7 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Se ha agregado /std:clatest
al compilador de C
Este modificador se comporta como el modificador /std:c++latest
del compilador de C++. El modificador habilita todas las características del compilador y de la biblioteca estándar implementadas actualmente y propuestas para el siguiente borrador del estándar de C, así como algunas características en curso y experimentales.
Biblioteca estándar de C++
Ahora se admite la biblioteca <print>
. Consulte P2093R14 salida con formato.
Implementadoviews::cartesian_product
.
Para obtener un resumen más amplio de los cambios realizados en la biblioteca de plantillas Estándar, consulte STL Changelog VS 2022 17.7.
using
conformidad
Anteriormente, la directiva using
podía hacer que los nombres de los espacios de nombres usados permanecieran visibles cuando no debían. Esto podía provocar que la búsqueda de nombres no cualificados encontrara un nombre en un espacio de nombres aunque no hubiera ninguna directiva using
activa.
Estos son algunos ejemplos del comportamiento nuevo y antiguo.
Las referencias de los siguientes comentarios a "(1)" significan la llamada a f<K>(t)
en el espacio de nombres 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>());
}
}
El mismo problema subyacente puede provocar que el código que antes se compilaba ahora sea rechazado:
#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;
}
Mejoras de cumplimiento en Visual Studio 2022, versión 17.6
Visual Studio 2022, versión 17.6 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Las asignaciones volatile
compuestas ya no están en desuso
En C++20 se dejó de usar la aplicación de determinados operadores a tipos calificados con volatile
. Por ejemplo, cuando se compila el siguiente código con cl /std:c++20 /Wall test.cpp
:
void f(volatile int& expr)
{
++expr;
}
El compilador produce test.cpp(3): warning C5214: applying '++' to an operand with a volatile qualified type is deprecated in C++20
.
En C++20, se dejaron de usar los operadores de asignaciones compuestas (operadores de tipo @=
). En C++23, los operadores compuestos excluidos en C++20 ya no están en desuso. Por ejemplo, en C++23, el siguiente código no genera una advertencia, mientras que sí lo hace en C++20:
void f(volatile int& e1, int e2)
{
e1 += e2;
}
Para obtener más información sobre este cambio, consulte CWG:2654.
La reescritura de igualdad en expresiones no es un cambio importante (P2468R2)
En C++20, P2468R2 cambió el compilador para aceptar código como el siguiente:
struct S
{
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} != S{};
El compilador acepta este código, lo que significa que el compilador es más estricto con código como el siguiente:
struct S
{
operator bool() const;
bool operator==(const S&);
};
bool b = S{} == S{};
La versión 17.5 del compilador acepta este programa. La versión 17.6 del compilador lo rechaza. Para corregirlo, agregue const
a operator==
para eliminar la ambigüedad. O bien agregue un operator!=
correspondiente a la definición como se muestra en el siguiente ejemplo:
struct S
{
operator bool() const;
bool operator==(const S&);
bool operator!=(const S&);
};
bool b = S{} == S{};
Las versiones 17.5 y 17.6 del compilador de Microsoft C/C++ aceptan el programa anterior y llaman a S::operator==
.
El modelo de programación general descrito en P2468R2 indica que si hay un operator!=
correspondiente para un tipo, normalmente suprime el comportamiento de reescritura. Agregar un operator!=
correspondiente es la corrección que se recomienda para el código compilado anteriormente en C++17. Si desea obtener más información, consulte Modelo de programación.
Mejoras de conformidad en Visual Studio 2022, versión 17.4
Visual Studio 2022, versión 17.4 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Tipos subyacentes de enum
sin ámbito sin tipo fijo
En versiones de Visual Studio anteriores a Visual Studio 2022 versión 17.4, el compilador de C++ no determinaba correctamente el tipo subyacente de una enumeración sin ámbito sin tipo base fijo. En /Zc:enumTypes
, ahora implementamos correctamente el comportamiento estándar.
El estándar de C++ requiere que el tipo subyacente de enum
sea lo suficientemente grande como para contener todos los enumeradores en tal enum
. Los enumeradores suficientemente grandes pueden establecer el tipo subyacente de enum
en unsigned int
, long long
o unsigned long long
. Anteriormente, estos tipos de enum
siempre tenían un tipo subyacente de int
en el compilador de Microsoft, independientemente de los valores del enumerador.
Cuando está habilitada, la opción /Zc:enumTypes
es un posible cambio importante de archivo binario y de origen. Está desactivada de manera predeterminada y no la habilita /permissive-
, porque la corrección podría afectar a la compatibilidad binaria. Algunos tipos de enumeración cambian de tamaño cuando se habilita la corrección compatible. Algunos encabezados de Windows SDK incluyen estas definiciones de enumeración.
Ejemplo
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 una definición de enum
sin ningún tipo subyacente fijo
En versiones de Visual Studio anteriores a Visual Studio 2022 versión 17.4, el compilador de C++ no modelaba correctamente los tipos de enumeradores. Podía suponer un tipo incorrecto en enumeraciones sin un tipo subyacente fijo antes de la llave de cierre de la enumeración. En /Zc:enumTypes
, ahora el compilador implementa correctamente el comportamiento estándar.
El estándar C++ especifica que, en la definición de una enumeración sin un tipo subyacente fijo, los inicializadores determinan los tipos de enumeradores. O bien, para los enumeradores sin inicializador, por el tipo del enumerador anterior (teniendo en cuenta el desbordamiento). Anteriormente, estos enumeradores siempre recibían el tipo deducido de la enumeración, con un marcador de posición para el tipo subyacente (normalmente int
).
Cuando está habilitada, la opción /Zc:enumTypes
es un posible cambio importante de archivo binario y de origen. Está desactivada de manera predeterminada y no la habilita /permissive-
, porque la corrección podría afectar a la compatibilidad binaria. Algunos tipos de enumeración cambian de tamaño cuando se habilita la corrección compatible. Algunos encabezados de Windows SDK incluyen estas definiciones de enumeración.
Ejemplo
enum Enum {
A = 'A',
B = sizeof(A)
};
static_assert(B == 1); // previously failed, now succeeds under /Zc:enumTypes
En este ejemplo, el enumerador A
debe tener el tipo char
antes de la llave de cierre de la enumeración, por lo que B
se debe inicializar mediante sizeof(char)
. Antes de la corrección /Zc:enumTypes
, A
tenía el tipo de enumeración Enum
con un tipo subyacente deducido int
y B
se inicializaba mediante sizeof(Enum)
, o 4.
Mejoras de cumplimiento en Visual Studio 2022, versión 17.3
Visual Studio 2022, versión 17.3 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
C: se ha mejorado la comprobación de compatibilidad del modificador entre punteros
El compilador de C no comparaba correctamente los modificadores entre punteros, especialmente void*
. Este defecto podía dar lugar a un diagnóstico incorrecto de incompatibilidad entre const int**
y void*
y compatibilidad entre int* volatile*
y void*
.
Ejemplo
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
}
Mejoras de cumplimiento en Visual Studio 2022, versión 17.2
Visual Studio 2022, versión 17.2 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Advertencias de caracteres bidireccionales no terminados
La versión 17.2 de Visual Studio 2022 agrega la advertencia de nivel 3 C5255 para los caracteres bidireccionales Unicode no terminados en comentarios y cadenas. La advertencia aborda una preocupación de seguridad descrita en Origen de troyanos: vulnerabilidades invisibles de Nicholas Boucher y Ross Anderson. Para obtener más información sobre los caracteres bidireccionales Unicode, vea Anexo del estándar Unicode® 9: ALGORITMO BIRECCIONAL DE UNICODE.
La advertencia C5255 solo aborda los archivos que, después de la conversión, contienen caracteres bidireccionales Unicode. Esta advertencia se aplica a los archivos UTF-8, UTF-16 y UTF-32, por lo que se debe proporcionar la codificación de origen adecuada. Este cambio se trata de un cambio que afecta directamente al código fuente.
Ejemplo (antes y después)
En las versiones de Visual Studio anteriores a la versión 17.2 de Visual Studio 2022, un carácter bidireccional no terminado no generaba una advertencia. En la versión 17.2 de Visual Studio 2022 se produce la advertencia 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
La versión 17.2 de Visual Studio 2022 corrige un error en <charconv>
from_chars()
float
reglas de desempate que generaron resultados incorrectos. Este error afectaba a las cadenas decimales que estaban en el punto medio exacto de los valores consecutivos float
, dentro de un intervalo estrecho. (Los valores más pequeños y más grandes afectados fueron 32768.009765625
y 131071.98828125
, respectivamente). La regla de desempate quería redondear a " igual ", y " igual " resultó ser hacia "abajo", pero la aplicación redondeó incorrectamente hacia "arriba" (double
no se vio afectado). Para obtener más información y detalles de implementación, consulte microsoft/STL#2366.
Este cambio afecta al comportamiento del entorno de ejecución en el intervalo de casos especificado.
Ejemplo
// 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");
}
En las versiones anteriores a la versión 17.2 de Visual Studio 2022:
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.
En Visual Studio 2022, versión 17.2 y 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__
pone __STDC__
a disposición de C
El estándar de C requiere que una implementación de C conforme defina __STDC__
como 1
. Debido al comportamiento de UCRT, que no expone funciones POSIX cuando __STDC__
es 1
, no es posible definir esta macro para C de forma predeterminada sin introducir cambios importantes en las versiones de lenguaje estable. Visual Studio 2022, versión 17.2 y posteriores, agrega una opción de conformidad, /Zc:__STDC__
, que define esta macro. No hay ninguna versión negativa de la opción. Actualmente, tenemos previsto usar esta opción de forma predeterminada para versiones futuras de C.
Este cambio se trata de un cambio que afecta directamente al código fuente. Se aplica cuando el modo C11 o C17 está habilitado, /std:c11
o /std:c17
, y se especifica /Zc:__STDC__
.
Ejemplo
// 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__
*/
Advertencia para llaves que faltan
La advertencia C5246 notifica que faltan llaves durante la inicialización agregada de un subobjeto. Antes de la versión 17.2 de Visual Studio 2022, la advertencia no controlaba el caso de un struct
o union
anónimo.
Este cambio se trata de un cambio que afecta directamente al código fuente. Se aplica cuando está habilitada la advertencia C5246 desactivada de forma predeterminada.
Ejemplo
En la versión 17.2 de Visual Studio 2022, este código ahora produce un error:
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, agregue llaves al inicializador:
void f()
{
S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}
Mejoras de cumplimiento en Visual Studio 2022, versión 17.1
Visual Studio 2022, versión 17.1 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Detección de valores predeterminados de captura con un formato incorrecto en expresiones lambda no locales
El estándar de C++ solo permite que una expresión lambda en el ámbito de bloque tenga un valor predeterminado de captura. En Visual Studio 2022, versiones 17.1 y posteriores, el compilador detecta cuándo no se permite un valor predeterminado de captura en una expresión lambda no local. Emite una nueva advertencia de nivel 4, C5253.
Este cambio se trata de un cambio que afecta directamente al código fuente. Se aplica en cualquier modo que use el nuevo procesador lambda: /Zc:lambda
, /std:c++20
o /std:c++latest
.
Ejemplo
En Visual Studio 2022 versión 17.1, este código ahora emite un error:
#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 corregir este problema, quite el valor predeterminado de captura:
#pragma warning(error:5253)
auto incr = [](int value) { return value + 1; };
C4028 ahora es C4133 para operaciones de función a puntero
Antes de la versión 17.1 de Visual Studio 2022, el compilador notificaba un mensaje de error incorrecto en determinadas comparaciones de puntero a función en el código de C. Se informó del mensaje incorrecto al comparar dos punteros de función que tenían los mismos recuentos de argumentos, pero tipos incompatibles. Ahora, se emite una advertencia diferente que se queja sobre la incompatibilidad de puntero a función en lugar del error de coincidencia de parámetros de función.
Este cambio se trata de un cambio que afecta directamente al código fuente. Se aplica cuando el código se compila como C.
Ejemplo
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)'
Error en static_assert
no dependiente
En Visual Studio 2022, versión 17.1 y posteriores, si la expresión asociada a una instancia de static_assert
no es una expresión dependiente, el compilador la evalúa cuando se analiza. Si la expresión se evalúa como false
, el compilador emite un error. Anteriormente, si static_assert
estaba dentro del cuerpo de una plantilla de función (o dentro del cuerpo de una función miembro de una plantilla de clase), el compilador no realizaría este análisis.
Este cambio se trata de un cambio que afecta directamente al código fuente. Se aplica en cualquier modo que implique /permissive-
o /Zc:static_assert
. Este cambio de comportamiento se puede deshabilitar mediante la opción del compilador /Zc:static_assert-
.
Ejemplo
En la versión 17.1 de Visual Studio 2022, este código ahora produce un error:
template<typename T>
void f()
{
static_assert(false, "BOOM!");
}
Para corregir este problema, haga que la expresión sea dependiente. Por ejemplo:
template<typename>
constexpr bool dependent_false = false;
template<typename T>
void f()
{
static_assert(dependent_false<T>, "BOOM!");
}
Con este cambio, el compilador solo emite un error si se crea una instancia de la plantilla de función f
.
Mejoras de conformidad en Visual Studio 2022, versión 17.0
Visual Studio 2022, versión 17.0 contiene las siguientes mejoras de conformidad, correcciones de errores y cambios de comportamiento del compilador de Microsoft C/C++.
Advertencia sobre el ancho del campo de bits para el tipo de enumeración
Al declarar una instancia de un tipo de enumeración como un campo de bits, el ancho del campo de bits tiene que alojar todos los valores posibles de la enumeración. De lo contrario, el compilador emite un mensaje de diagnóstico. Considere este ejemplo:
enum class E : unsigned { Zero, One, Two };
struct S {
E e : 1;
};
Un programador podría esperar que el miembro de la clase S::e
pueda contener cualquiera de los valores proporcionados explícitamente con nombre enum
. Dado el número de elementos de enumeración, esto no es posible. El campo de bits no puede cubrir el intervalo de valores proporcionados de forma explícita de E
(conceptualmente, el dominio de E
). Para solucionar el problema de que el ancho del campo de bits no es lo suficientemente grande para el dominio de la enumeración, se agrega una nueva advertencia (desactivada de manera predeterminada) a 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 };
^
Este comportamiento del compilador es un cambio importante de origen y binario que afecta a todos los modos /std
y /permissive
.
Error en la comparación de punteros ordenados con nullptr
o 0
El estándar de C++ permitía accidentalmente una comparación de puntero ordenada con nullptr
o 0. Por ejemplo:
bool f(int *p)
{
return p >= 0;
}
El documento WG21 N3478 ha quitado esta supervisión. Este cambio se implementa en MSVC. Cuando el ejemplo se compila mediante /permissive-
(y /diagnostics:caret
), emite el error siguiente:
t.cpp(3,14): error C7664: '>=': ordered comparison of pointer and integer zero ('int *' and 'int')
return p >= 0;
^
Este comportamiento del compilador es un cambio importante de origen y binario que afecta al código compilado mediante los modos /permissive-
y /std
.