Compartir a través de


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 ir directamente a los cambios de una versión específica, use los vínculos En este artículo en la parte superior de este artículo.

En este documento se enumeran los cambios en Visual Studio 2022.

Para los cambios en versiones anteriores de Visual Studio:

Versión Vínculo mejoras de conformidad
2019 Mejoras de conformidad de C++ en Visual Studio 2019
2017 Mejoras de conformidad de C++ en Visual Studio 2017
2003-2015 Novedades de Visual C++ de 2003 a 2015

Mejoras de conformidad en Visual Studio 2022, versión 17.12

La versión 17.12 de Visual Studio 2022 incluye 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.12.

_com_ptr_t::operator bool() ahora es explícito

Se trata de un cambio importante de origen o binario.

La conversión implícita a bool desde _com_ptr_t instancias puede ser sorprendente o provocar errores del compilador. Las funciones de conversión implícitas no son recomendables por las Directrices básicas de C++ (C.164) y _com_ptr_t contienen conversiones implícitas en bool y Interface*. Estas dos conversiones implícitas pueden provocar ambigüedades.

Para ayudar a solucionar esto, la conversión a bool ahora es explícita. La conversión a Interface* no cambia.

Se proporciona una macro para no participar en este nuevo comportamiento y restaurar la conversión implícita anterior. Compile con para /D_COM_DISABLE_EXPLICIT_OPERATOR_BOOL no participar en este cambio. Se recomienda modificar el código para que no se base en conversiones implícitas.

Por ejemplo:

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

Las expresiones constantes ya no siempre noexcept están en modo permisivo

Se trata de un cambio importante de origen o binario.

Una expresión constante siempre noexceptera , incluso si implicaba una llamada de función a una función declarada con una especificación de excepción potencialmente iniciada. Esta redacción se quitó en C++17, aunque el compilador de Microsoft Visual C++ todavía lo admitía en modo en /permissive todas las versiones del lenguaje C++.

Este /permissive comportamiento de modo se quita. Las expresiones constantes ya no reciben un comportamiento implícito especial.

El noexcept especificador en constexpr las funciones ahora se respeta en todos los modos. Este cambio es necesario para la implementación correcta de las resoluciones de problemas principales posteriores que dependen del comportamiento estándar noexcept .

Por ejemplo:

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

Mejoras de conformidad en Visual Studio 2022, versión 17.11

La versión 17.11 de Visual Studio 2022 incluye 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.

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 a println(stdout);
  • println(FILE* stream); es equivalente a println(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

La versión 17.10 de Visual Studio 2022 incluye 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, 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:

typeof
typeof_unqual

Lo siguiente está disponible para todas las versiones del lenguaje C:

__typeof__
__typeof_unqual__

Biblioteca estándar de C++

Características de C++23

  • formattable, range_format, format_kind y set_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.

usingconformidad

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 "incluso", e "incluso" era "abajo", pero la implementación redondeada incorrectamente "arriba" (double no se vio afectada). Para obtener más información e información sobre la 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++20o /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 .

Vea también

Conformidad del lenguaje Microsoft C/C++