C++ Visual Studio 2022 中的改进、行为更改和错误修复

简介: C++ Visual Studio 2022 中的改进、行为更改和错误修复

Visual Studio 2022 版本 17.4 中的一致性改进

8ce6f350d86948d5923b3834739b98cc.png

Visual Studio 2022 版本 17.4 包含 Microsoft C/C++ 编译器中的以下一致性改进、错误修复和行为更改

        作用域的基础类型没有固定类型enum


在 Visual Studio 2022 版本 17.4 之前的 Visual Studio 版本中,C++编译器未正确确定没有固定基类型的无作用域枚举的基础类型


C++ 标准要求枚举的基础类型足够大,以容纳该枚举中的所有枚举器。足够大的枚举器可以将枚举的基础类型设置为无符号 int、long long 或无符号 long long。以前,无论枚举器值如何,此类枚举类型在 Microsoft 编译器中始终具有基础类型int


启用后,/Zc:enumType选项是潜在的源和二进制中断性更改。默认情况下,它处于关闭状态,并且不由/允许启用,因为修复可能会影响二进制兼容性。启用一致性修复时,某些枚举类型会更改大小。某些 Windows SDK 标头包含此类枚举定义。


#include<stdio.h>
enum Unsigned
{
    A = 0xFFFFFFFF //值“A”不适合“int”。
};
//以前,未通过此static_assert。现在使用 /Zc:enumTypes 传递。
static_assert(std::is_same_v<std::underlying_type_t<Unsigned>, unsigned int>);
template <typename T>
void f(T x)
{
}
int main()
{
    // 以前称为 f<int>,现在称为 f<unsigned int>。
    f(+A);
}
//以前,这个枚举将具有底层类型的“int”,但标准C++要求它具有
//64 位基础类型。使用 / Zc:enumTypes 将此枚举的大小从 4 更改为 8,这可能会
//影响与使用早期编译器版本或不使用开关编译的代码的二进制兼容性。
enum Changed
{
    X = -1,
    Y = 0xFFFFFFFF
};


 定义中没有固定基础类型的枚举器类型enum

在 Visual Studio 2022 版本 17.4 之前的 Visual Studio 版本中,C++编译器未正确确定没有固定基类型的无作用域枚举的基础类型


C++ 标准要求枚举的基础类型足够大,以容纳该枚举中的所有枚举器。足够大的枚举器可以将枚举的基础类型设置为无符号 int、long long 或无符号 long long。以前,无论枚举器值如何,此类枚举类型在 Microsoft 编译器中始终具有基础类型int。


启用后,/Zc:enumType选项是潜在的源和二进制中断性更改。默认情况下,它处于关闭状态,并且不由/允许启用,因为修复可能会影响二进制兼容性。启用一致性修复时,某些枚举类型会更改大小。某些 Windows SDK 标头包含此类枚举定义。


举例

enum Enum {
    A = 'A',
    B = sizeof(A)
};
static_assert(B == 1); // 以前失败,现在在 /Zc:enumType 下成功


枚举器应在枚举的右大括号之前具有char类型,因此应使用 进行初始化。在 /Zc:enumType修复之前,具有枚举类型,具有推导的底层类型int,并使用 或 4 进行初始化。ABsizeof(char)AEnumBsizeof(Enum)


Visual Studio 2022 版本 17.3 中的一致性改进

Visual Studio 2022 版本 17.3 包含 Microsoft C/C++ 编译器中的以下一致性改进、错误修复和行为更改。


     改进了指针之间的修饰符兼容性检查

尤其是 C 编译器没有正确比较指针之间的修饰符。此缺陷可能导致对两者之间的不相容性和两者之间的不相容性诊断不正确

void fn(void* pv) { (pv); }
int main()
{
    int t = 42;
    int* pt = &t;
    int* volatile * i = &pt;
    fn(i);    // 现在支持 C4090
    const int** j = &pt;
    fn(j);    //不再支持C4090
 }


Visual Studio 2022 版本 17.2 中的一致性改进

Visual Studio 2022 版本 17.2 包含 Microsoft C/C++ 编译器中的以下一致性改进、错误修复和行为更改。

未终止的双向字符警告

  • Visual Studio 2022 版本 17.2 为注释和字符串中未终止的 Unicode 双向字符添加了 3 级警告 C5255
  • 警告 C5255 仅处理转换后包含 Unicode 双向字符的文件。此警告适用于 UTF-8、UTF-16 和 UTF-32 文件,因此必须提供正确的源编码。此更改是源中断性更改。


示例(之前/之后)

代码举例


// bidi.cpp
int main() {
    const char *access_level = "user";
    //以下源代码行包含等效于的双向 Unicode 字符:
    if ( strcmp(access_level, “user‮ ⁦// Check if admin ⁩ ⁦”) ) {
    在大多数编辑器中,它呈现为:    if ( strcmp(access_level, "user") ) { // Check if admin
    if ( strcmp(access_level, "user‮ ⁦// Check if admin ⁩ ⁦") ) {
        printf("You are an admin.\n");
    }
    return 0;
}
/* 构建输出
双向.cpp(8): 警告 C5255:遇到未终止的双向字符:“U+202e”
双向.cpp(8): 警告 C5255:遇到未终止的双向字符:“U+2066”
*/

from_chars() float

Visual Studio 2022 版本 17.2 修复了产生错误结果的错误破坏规则。此错误影响了位于连续值的精确中点的十进制字符串,范围很窄。(受影响的最小值和最大值分别为 and。决胜规则想要舍入为“偶数”,“偶数”恰好是“向下”,但实现错误地舍入了“向上”

例  

// 
#include <cassert>
#include <charconv>
#include <cstdio>
#include <string_view>
#include <system_error>
using namespace std;
int main() {
    const double dbl  = 32768.009765625;
    const auto sv     = "32768.009765625"sv;
    float flt         = 0.0f;
    const auto result = from_chars(sv.data(), sv.data() + sv.size(), flt);
    assert(result.ec == errc{});
    printf("from_chars() returned: %.1000g\n", flt);
    printf("This rounded %s.\n", flt < dbl ? "DOWN" : "UP");
}
  • 在 Visual Studio 2022 版本 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.


  • 在 Visual Studio 2022 版本 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.0078125
This rounded DOWN.


__STDC__使可用于 C__STDC__


C 标准要求符合 C 的实现定义为 。由于 UCRT 的行为,它不会公开 POSIX 函数,因此默认情况下,如果不对稳定语言版本进行重大更改,则无法为 C 定义此宏

此更改是源中断性更改。当启用 C11 或 C17 模式时,它适用,/std:c11 或 /std:c17,以及 /Zc:__STDC__。

// 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
}
/* 命令行行为
C:\Temp>cl /EHsc /W4 /Zc:__STDC__ test__STDC__.c && test__STDC__
*/

缺少括号的警告


  • 警告 C5246 报告在子对象的聚合初始化期间缺少大括号。在 Visual Studio 2022 版本 17.2 之前,警告无法处理匿名者的情况。structunion
  • 此更改是源中断性更改。当启用默认关闭警告 C5246 时,它适用。

  • 在 Visual Studio 2022 版本 17.2 及更高版本中,此代码现在会导致错误:
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: '匿名结构或联合':子对象的初始化应括在大括号中‘
*/


  • 若要解决此问题,请向初始值设定项添加大括号
void f()
{
   S s = { { 1.0f, 2.0f, 3.14f, 4.0f } };
}


Visual Studio版本 17.1 中的一致性改进

Visual Studio 2022 版本 17.1 包含 Microsoft C/C++ 编译器中的以下一致性改进、错误修复和行为更改。


C++ 标准仅允许块作用域中的 lambda 表达式具有捕获默认值。在 Visual Studio 2022 版本 17.1 及更高版本中,编译器会检测何时不允许在非本地 lambda 表达式中使用捕获默认值。它会发出新的 4 级警告 C5253。

此更改是源中断性更改。它适用于使用新lambda处理器的任何模式:/Zc:lambda,/std:c++20或/std:c++latest。


在 Visual Studio 2022 版本 17.1 中,此代码现在发生错误:

#pragma warning(error:5253)
auto incr = [=](int value) { return value + 1; };
//capture_default.cpp(3,14):错误 C5253:非本地 lambda 不能具有捕获默认值
自动增量 = [=](整数值) { 返回值 + 1; };
//             ^

若要解决此问题,请删除捕获默认值:

#pragma warning(error:5253)

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


C4028 现在是 C4133,用于函数到指针操作


在 Visual Studio 2022 版本 17.1 之前,编译器在 C 代码中的某些指针到函数比较时报告了不正确的错误消息。当您比较两个具有相同参数计数但类型不兼容的函数指针时,报告了不正确的消息。现在,我们发出一个不同的警告,抱怨指针到函数不兼容,而不是函数参数不匹配。


此更改是源中断性更改。当代码编译为 C 时,它适用。

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

非依赖上的错误static_assert

在 Visual Studio 2022 版本 17.1 及更高版本中,如果与 a 关联的表达式不是依赖表达式,则编译器会在分析表达式后立即计算表达式。如果表达式的计算结果为 ,编译器将发出错误。以前,如果在函数模板的主体中(或在类模板的成员函数的主体中),编译器不会执行此分析。static_assertfalsestatic_assert


此更改是源中断性更改。它适用于任何暗示/允许或/Zc:static_assert的模式。可以使用 /Zc:static_assert 编译器选项禁用此行为更改。


在 Visual Studio 2022 版本 17.1 及更高版本中,此代码现在会导致错误:

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

若要解决此问题,请将表达式设置为依赖表达式。例如:

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


通过此更改,编译器仅在实例化函数模板时发出错误。

Visual Studio 2022 版本 17.0 中的一致性改进

Visual Studio 2022 版本 17.0 包含 Microsoft C/C++ 编译器中的以下一致性改进、错误修复和行为更改。


枚举类型的位域宽度警告


将枚举类型的实例声明为位域时,位域的宽度必须容纳枚举的所有可能值。否则,编译器将发出诊断消息。请考虑以下示例: 考虑:

enum class E : unsigned { Zero, One, Two };
struct S {
  E e : 1;
};


你可能希望类成员可以保存任何显式命名的值。给定枚举元素的数量,这是不可能的。位域不能涵盖显式提供的值的范围(概念上是域)。为了解决位域宽度不足以容纳枚举域的问题,向 MSVC 添加了一条新的(默认情况下为关闭)警告:S::eenumEE


t.cpp(4,5): 警告 C5249: 类型为“E”的“S::e”命名了枚举器,其值无法在给定位字段宽度“1”中表示。

 E e : 1;

   ^

t.cpp(1,38):注:参见值为“2”的枚举器“E::Two”

枚举类 E : 无符号 { 零, 一, 二 };

                                    ^

此编译器行为是影响所有/std和/允许模式的源和二进制中断性更改。


与 0 的有序指针比较时出错nullptr


C++标准无意中允许对 0 进行有序指针比较。例如:nullptr


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

使用 /permissive-(and/diagnostics:caret) 编译示例时,它会发出以下错误:

t.cpp(3,14):错误 C7664:“>=”:指针和整数零(“int *”和“int”)的有序比较
   返回 p >= 0;
            ^


此编译器行为是源和二进制中断性更改,会影响使用/允许全部/std模式编译的代码。

完结撒花!!!

相关文章
|
4月前
|
编译器 开发工具 C++
【Python】已解决error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build
【Python】已解决error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build
2261 0
|
5月前
|
存储 分布式数据库 API
技术好文:VisualC++查看文件被哪个进程占用
技术好文:VisualC++查看文件被哪个进程占用
|
2月前
|
C++ 内存技术
[转]Visual C++内嵌swf文件并播放
[转]Visual C++内嵌swf文件并播放
|
3月前
|
安全 编译器 C++
Microsoft Visual C++ Redistributable的作用主要体现以及可以删除吗?
这些是Microsoft Visual C++不同版本的Redistributable安装包,用于32位系统,确保相关应用正常运行。它们提供C++运行时环境,简化部署流程,支持第三方库及框架,并确保应用兼容性。定期更新可修复问题并引入新功能。在空间有限或需解决程序冲突时可考虑删除,但需谨慎操作以防影响应用稳定性和兼容性。删除前请确认无应用依赖,并通过控制面板安全卸载。
175 1
Microsoft Visual C++ Redistributable的作用主要体现以及可以删除吗?
|
3月前
|
安全 网络安全 数据安全/隐私保护
探索企业上网行为管理软件:C++ 的视角
在数字化企业环境中,上网行为管理软件至关重要,它不仅保障信息安全还优化网络资源分配。C++以高效和强大性能为基础,支持这类软件的开发。通过示例代码展示了如何使用C++捕获网络数据包、控制特定网址访问及分析网络流量模式,展现了C++在处理大规模网络数据方面的优势,满足企业对网络安全与管理的需求。
39 1
|
4月前
|
C++ Windows
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
在Windows上使用Visual Studio 2022进行FFmpeg和SDL2集成开发,首先安装FFmpeg至E:\msys64\usr\local\ffmpeg,然后新建C++控制台项目。在项目属性中,添加FFmpeg和SDL2的头文件及库文件目录。接着配置链接器的附加依赖项,包括多个FFmpeg及SDL2的lib文件。在代码中引入FFmpeg的`av_log`函数输出"Hello World",编译并运行,若看到"Hello World",即表示集成成功。详细步骤可参考《FFmpeg开发实战:从零基础到短视频上线》。
176 0
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
|
3月前
|
缓存 C++ Windows
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
Inno setup 脚本判断 Microsoft Visual C++ Redistributable 不同版本区别
|
3月前
|
编译器 C++ 开发者
Visual Studio属性表:在新项目中加入已配置好的C++库
通过以上步骤可以确保Visual Studio中新项目成功地加入了之前已配置好的C++库。这个过程帮助开发者有效地管理多个项目中共享的库文件,提升开发效率。
103 0
|
4月前
|
运维 NoSQL Redis
c++开发redis module问题之module根据Redis的角色采取不同的行为,如何解决
c++开发redis module问题之module根据Redis的角色采取不同的行为,如何解决
|
5月前
|
数据安全/隐私保护 C++
C++ 中的类是一种用户定义的数据类型,用于表示具有相似特征和行为的对象的模板。
C++ 中的类是一种用户定义的数据类型,用于表示具有相似特征和行为的对象的模板。