潜在的升级问题概述 (Visual C++)Overview of potential upgrade issues (Visual C++)

多年来,Microsoft Visual C++ 编译器已历经多次更改,而 C++ 语言本身、C++ 标准库、C 运行时 (CRT) 以及其他库(如 MFC 和 ATL)亦然。Over the years, the Microsoft Visual C++ compiler has undergone many changes, along with changes in the C++ language itself, the C++ Standard Library, the C runtime (CRT), and other libraries such as MFC and ATL. 因此,在从 Visual Studio 的早期版本升级应用程序时,可能遇到编译器和链接器错误,以及先前已完全编译的代码中的警告。As a result, when upgrading an application from an earlier version of Visual Studio you might encounter compiler and linker errors and warnings in code that previously compiled cleanly. 原始基本代码越早,发生此类错误的可能性越大。The older the original code base, the greater the potential for such errors. 本概述总结了可能遇到的最常见类型的问题,并提供有关详细信息的链接。This overview summarizes the most common classes of issues you are likely to encounter, and provides links to more detailed information.

注意:过去我们建议应以增量方式执行跨多版本 Visual Studio 的升级,一次执行一个版本。Note: In the past, we have recommended that upgrades that span several versions of Visual Studio should be performed incrementally one version at a time. 现在我们不再推荐这种方法。We no longer recommend this approach. 我们发现,无论基本代码有多早,采用升级至最新版本 Visual Studio 的方法几乎总是更简单。We have found that it is almost always simpler to upgrade to the most current version of Visual Studio no matter how old the code base.

可将有关升级过程的问题或评论发送至 vcupgrade@microsoft.com。Questions or comments about the upgrade process can be sent to vcupgrade@microsoft.com.

库和工具集依赖项Library and toolset dependencies

在将应用程序升级至 Visual Studio 的新版本时,强烈建议升级应用程序链接的所有库和 DLL,这在许多情况下是必要的。When upgrading an application to a new version of Visual Studio, it is strongly advisable and in many cases necessary to also upgrade all libraries and DLLs that the application links to. 这要求你拥有访问源代码的权限,或库供应商能提供使用相同的主版本编译器进行编译的新二进制文件。This requires either that you have access to the source code, or that the library vendor can provide new binary files compiled with the same major version of the compiler. 若下列条件之一为 true,则可跳过此部分,此部分介绍有关二进制兼容性的详细信息。If one of these conditions is true, then you can skip this section, which deals with the details of binary compatibility. 如果不符合以下任一条件,则可能无法在已升级的应用程序中使用库。If neither of these are the case, then you might not be able to use the libraries in your upgraded application. 此部分的信息将帮助你了解是否可以继续进行升级。The information in this section will help you understand whether you can proceed with the upgrade.


.obj 和 .lib 文件格式都定义完善且很少更改。The .obj and .lib file formats are well-defined and rarely change. 有时会对这些文件格式进行添加,但这些添加通常不会影响较新工具集使用由较旧工具集生成的对象文件和库的能力。Sometimes additions are made to these file formats, but these additions generally do not affect the ability of newer toolsets to consume object files and libraries produced by older toolsets. 但如果使用 /GL(全程序优化)进行编译,则是一个大的例外。The one big exception here is if you compile using /GL (Whole Program Optimization). 如果使用 /GL 进行编译,生成的对象文件只能使用生成它时所用的同一工具集进行链接。If you compile using /GL, the resulting object file can only be linked using the same toolset that was used to produce it. 因此,如果使用 /GL 和 Visual Studio 2017 (v141) 编译器生成对象文件,则必须使用 Visual Studio 2017 (v141) 链接器对其进行链接。So, if you produce an object file with /GL and using the Visual Studio 2017 (v141) compiler, you must link it using the Visual Studio 2017 (v141) linker. 这是由于对象文件中的内部数据结构在各主版本的工具集之间不稳定,且较新的工具集无法识别较旧的数据格式。This is because the internal data structures within the object files are not stable across major versions of the toolset and newer toolsets do not understand the older data formats.

C++ 不具备稳定的应用程序二进制接口 (ABI)。C++ does not have a stable application binary interface (ABI). Visual Studio 为版本的所有次要版本维护稳定的 C++ ABI。Visual Studio maintains a stable C++ ABI for all minor versions of a release. 例如,Visual Studio 2017 及其所有更新均兼容二进制文件。For example, Visual Studio 2017 and all its updates are binary compatible. 但 ABI 不一定具有跨 Visual Studio 主版本的兼容性(2015 和 2017 除外,它们兼容二进制文件)。But the ABI is not necessarily compatible across major versions of Visual Studio (except for 2015 and 2017, which are binary compatible). 也就是说,可以对 C++ 类型布局、名称修饰、异常处理和 C++ ABI 的其他部件进行重大更改。That is, we may make breaking changes to C++ type layout, name decoration, exception handling, and other parts of the C++ ABI. 因此,如果对象文件具有包含 C++ 链接的外部符号,则该对象文件可能无法与由其他主版本工具集生成的对象文件正确链接。Thus, if you have an object file that has external symbols with C++ linkage, that object file may not link correctly with object files produced with a different major version of the toolset. 请注意:“可能无效”具有多种可能的结果:链接可能彻底失效(例如,如果名称修饰已更改);链接可能成功,但在运行时可能无效(例如,如果类型布局已更改);或在许多情况下,虽然可能出现一些状况,但一切运行正常。Note that here, "may not work" has many possible outcomes: the link may fail entirely (e.g. if name decoration changed), the link may succeed and things may not work at runtime (e.g. if type layout changed), or things may happen to work in many cases and nothing will go wrong. 另请注意,尽管 C++ ABI 不稳定,但 COM 所需的 C ABI 和 C++ ABI 的子集是稳定的。Note also that while the C++ ABI is not stable, the C ABI and the subset of the C++ ABI required for COM are stable.

如果链接到导入库,保留 ABI 兼容性的 Visual Studio 可再发行库的更高版本可在运行时使用。If you link to an import library, any later version of the Visual Studio redistributable libraries that preserve ABI compatibility may be used at runtime. 例如,如果使用 Visual Studio 2015 Update 3 工具集编译和链接应用,可使用任何 Visual Studio 2017 可再发行库,因为 2015 和 2017 库具有保留的二进制后向兼容性。For example, if your app is compiled and linked using the Visual Studio 2015 Update 3 toolset, you can use any Visual Studio 2017 redistributable, because the 2015 and 2017 libraries have preserved backward binary compatibility. 反之则不然。不能将可再发行库用于低于之前生成代码所使用的工具集版本的版本,即使其具有可兼容 ABI,也是如此。The reverse is not true; you can't use a redistributable for an earlier version of the toolset than you used to build your code, even if they have a compatible ABI.


如果使用 Visual Studio C++ 库头文件的特定版本来编译源文件(通过 #including 标头),生成的对象文件必须与相同版本的库链接。If you compile a source file using a particular version of the Visual Studio C++ libraries header files (by #including the headers), the resulting object file must be linked with the same version of the libraries. 例如,如果使用 Visual Studio 2015 Update 3 <immintrin.h> 编译源文件,则必须使用 Visual Studio 2015 Update 3 vcruntime 库进行链接。So, for example, if your source file is compiled with the Visual Studio 2015 Update 3 <immintrin.h>, you must link with the Visual Studio 2015 Update 3 vcruntime library. 同样地,如果使用 Visual Studio 2017 版本 15.5 <iostream> 编译源文件,则必须使用 Visual Studio 2017 版本 15.5 标准 C++ 库 msvcprt 进行链接。Similarly, if your source file is compiled with the Visual Studio 2017 version 15.5 <iostream>, you must link with the Visual Studio 2017 version 15.5 Standard C++ library, msvcprt. 不支持混合与匹配。Mixing-and-matching is not supported.

对于 C++ 标准库,从 Visual Studio 2010 起,通过在标准标头中使用 #pragma detect_mismatch 显示禁止混合与匹配。For the C++ Standard Library, mixing-and-matching has been explicitly disallowed via use of #pragma detect_mismatch in the standard headers since Visual Studio 2010. 如果尝试链接不兼容的对象文件,或尝试与错误的标准库链接,链接将失败。If you try to link incompatible object files, or if you try to link with the wrong standard library, the link will fail.

CRT 向来不支持混合与匹配,但通常还是能使用混合与匹配(至少在 Visual Studio 2015 和通用 CRT 之前,都是如此),这是因为 API 接口一直以来的变化不大。For the CRT, mixing-and-matching was never supported, but it often just worked, at least until Visual Studio 2015 and the Universal CRT, because the API surface did not change much over time. 通用 CRT 中断了后向兼容性,以便我们将来维护向后兼容性。The Universal CRT broke backwards compatibility so that in the future we can maintain backwards compatibility. 也就是说,将来我们不打算引入新的、已进行版本管理的通用 CRT 二进制文件。In other words, we have no plans to introduce new, versioned Universal CRT binaries in the future. 现有的通用 CRT 已更新就绪。Instead, the existing Universal CRT is now updated in-place.

为了提供与使用早期版本的 Microsoft C 运行时标头编译的对象文件(和库)的部分链接兼容性,我们提供库 legacy_stdio_definitions.lib,用于 Visual Studio 2015 及更高版本。To provide partial link compatibility with object files (and libraries) compiled with older versions of the Microsoft C Runtime headers, we provide a library, legacy_stdio_definitions.lib, with Visual Studio 2015 and later. 此库为大部分从通用 CRT 删除的函数和数据导出提供兼容性符号。This library provides compatibility symbols for most of the functions and data exports that were removed from the Universal CRT. legacy_stdio_definitions.lib 提供的兼容性符号集足以满足大多数依赖项,包括 Windows SDK 所包含的库中的所有依赖项。The set of compatibility symbols provided by legacy_stdio_definitions.lib is sufficient to satisfy most dependencies, including all of the dependencies in libraries included in the Windows SDK. 但是,对于某些从通用 CRT 删除的符号,则无法提供类似的兼容性符号。However, there are some symbols that were removed from the Universal CRT for which it is not possible to provide compatibility symbols like this. 这些符号包括一些函数(如 __iob_func)和数据导出(如 __imp___iob、__imp___pctype、__imp___mb_cur_max)。These symbols include some functions (e.g., __iob_func) and the data exports (e.g., __imp___iob, __imp___pctype, __imp___mb_cur_max).

如果静态库由较旧版本的 C 运行时标头生成,建议采取下列操作(按以下顺序):If you have a static library that was built with an older version of the C Runtime headers, we recommend the following actions (in this order):

  1. 使用 Visual Studio 2017 和通用 CRT 标头重新生成静态库,以支持与通用 CRT 的链接。Rebuild the static library using Visual Studio 2017 and the Universal CRT headers to support linking with the Universal CRT. 这是完全受支持的选项,也是最佳选项。This is the fully supported (and thus best) option.

  2. 如果无法(或不希望)重新生成静态库,可以尝试使用 legacy_stdio_definitions.lib 进行链接。If you cannot (or do not want to) rebuild the static library, you may try linking with legacy_stdio_definitions.lib. 如果它满足静态库的链接时间依赖项,则需要彻底测试静态库在二进制文件中的使用情况,以确保对通用 CRT 所做的行为更改不会对其造成不利影响。If it satisfies the link-time dependencies of your static library, you will want to thoroughly test the static library as it is used in the binary, to make sure that it is not adversely affected by any of the behavioral changes that were made to the Universal CRT.

  3. 如果 legacy_stdio_definitions.lib 不能满足静态库的依赖项,或库不适用于通用 CRT(由于上述行为更改),则建议将静态库封装到与 Microsoft C 运行时的正确版本链接的 DLL。If your static library’s dependencies are not satisfied by legacy_stdio_definitions.lib or if the library does not work with the Universal CRT due to the aforementioned behavioral changes, we would recommend encapsulating your static library into a DLL that you link with the correct version of the Microsoft C Runtime. 例如,如果使用 Visual Studio 2013 生成静态库,则也需要使用 Visual Studio 2013 和 Visual Studio 2013 C++ 库来生成此 DLL。For example, if the static library was built using Visual Studio 2013, you would want to build this DLL using Visual Studio 2013 and the Visual Studio 2013 C++ libraries as well. 通过将库构建到 DLL 中,可封装实现的详细信息(此详细信息是在特定版本 Microsoft C 运行时上的它的依赖项)。By building the library into a DLL, you encapsulate the implementation detail that is its dependency on a particular version of the Microsoft C Runtime. (注意:需要小心的是 DLL 接口不会泄露其使用的是哪种 C 运行时的详细信息,例如通过返回跨 DLL 边界的 FILE*,或通过返回 malloc 分配的指针并让调用方释放它。)(Note that you will want to be careful that the DLL interface does not leak details of which C Runtime it uses, e.g. by returning a FILE* across the DLL boundary or by returning a malloc-allocated pointer and expecting the caller to free it.)

在单个进程中使用多个 CRT 本身不是问题(实际上,大多数进程最终将加载多个 CRT DLL;例如 Windows 操作系统组件依赖于 msvcrt.dll,而 CLR 也依赖于它自己的专用 CRT)。Use of multiple CRTs in a single process is not in and of itself problematic (indeed, most processes will end up loading multiple CRT DLLs; for example, Windows operating system components will depend on msvcrt.dll and the CLR will depend on its own private CRT). 当混杂不同 CRT 中的状态时,会出现问题。Problems arise when you jumble state from different CRTs. 例如,不应使用 msvcr110.dll!malloc 分配内存,也不应使用 msvcr120.dll!free 取消分配内存,不应尝试使用 msvcr110!fopen 打开文件,也不应尝试使用 msvcr120!fread 读取文件。For example, you should not allocate memory using msvcr110.dll!malloc and attempt to deallocate that memory using msvcr120.dll!free, and you should not attempt to open a FILE using msvcr110!fopen and attempt to read from that FILE using msvcr120!fread. 只要不混杂不同 CRT 中的状态,就能安全地在单个进程中加载多个 CRT。As long as you don’t jumble state from different CRTs, you can safely have multiple CRTs loaded in a single process.

有关详细信息,请参阅将代码升级到通用 CRTFor more information, see Upgrade your code to the Universal CRT.

项目设置导致的错误Errors due to project settings

要开始升级进程,仅需在最新版本的 Visual Studio 中打开旧的 project/solution/workspace。To begin the upgrade process, simply open an older project/solution/workspace in the latest version of Visual Studio. Visual Studio 将基于旧的项目设置创建新项目。Visual Studio will create a new project based on the old project settings. 如果旧项目具有库,或包含非标准位置的硬编码路径,则当项目使用默认设置时,这些路径中的文件有可能对编译器不可见。If the older project has library or include paths that are hard-coded to non-standard locations, it is possible that the files in those paths won’t be visible to the compiler when the project uses the default settings. 有关详细信息,请参阅链接器 OutputFile 设置For more information, see Linker OutputFile setting.

一般情况下,现在是恰当组织项目代码的绝佳时机,以便简化项目维护,并尽可能加快已升级代码编译。In general, now is a great time to organize your project code properly in order to simplify project maintenance and help get your upgraded code compiling as quickly as possible. 如果已恰当组织源代码,且使用 Visual Studio 2010 或更高版本对旧项目进行编译,则可手动编辑新项目文件,以支持在旧编译器和新编译器上进行编译。If your source code is already well-organized, and your older project is compiled with Visual Studio 2010 or later, you can manually edit the new project file to support compilation on both the old and new compiler. 下面的示例演示了如何为 Visual Studio 2015 和 Visual Studio 2017 进行编译:The following example shows how to compile for both Visual Studio 2015 and Visual Studio 2017:

<PlatformToolset Condition="'$(VisualStudioVersion)'=='14.0'">v140</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15.0'">v141</PlatformToolset>

LNK2019:无法解析的外部符号LNK2019: Unresolved external

对于无法解析的符号,可能需要修复项目设置。For unresolved symbols, you might need to fix up your project settings.

  • 如果源文件位于非默认位置,你是否将路径添加到了项目的包含目录?If the source file is in a non-default location, did you add the path to the project’s include directories?

  • 如果在 .lib 文件中定义了外部符号,你是否在项目属性中指定了 lib 路径?正确版本的 .lib 文件是否位于此处?If the external is defined in a .lib file, have you specified the lib path in the project properties and is the correct version of the .lib file actually located there?

  • 是否尝试链接到由其他版本的 Visual Studio 编译的 .lib 文件?Are you attempting to link to a .lib file that was compiled with a different version of Visual Studio? 如果是,请参阅前面部分中关于库和工具集依赖项的内容。If so, see the previous section on library and toolset dependencies.

  • 调用站点处的参数类型是否匹配现有的函数重载?Do the types of the arguments at the call site actually match an existing overload of the function? 验证函数签名和调用函数的代码中的 typedef 的基础类型是否是你需要的类型。Verify the underlying types for any typedefs in the function’s signature and in the code that calls the function are what you expect them to be.

若要解决无法解析的符号错误,可以尝试使用 dumpbin.exe 来检查二进制文件中定义的符号。To troubleshoot unresolved symbol errors, you can try using dumpbin.exe to examine the symbols defined in a binary. 请尝试使用下面的命令行来查看在库中定义的符号:Try the following command line to view symbols defined in a library:

dumpbin.exe /LINKERMEMBER somelibrary.lib

/Zc:wchar_t(wchar_t 是本机类型)/Zc:wchar_t (wchar_t Is Native Type)

(在 Microsoft Visual C++ 6.0 和早期版本中,wchar_t 未作为内置类型实现,但在 wchar.h 中声明为用于 unsigned short 的 typedef。)C++ 标准要求 wchar_t 成为内置类型。(In Microsoft Visual C++ 6.0 and earlier, wchar_t was not implemented as a built-in type, but was declared in wchar.h as a typedef for unsigned short.) The C++ standard requires that wchar_t be a built-in type. 使用 typedef 版本可能导致可移植性问题。Using the typedef version can cause portability problems. 如果从早期版本的 Visual Studio 升级并遇到编译器错误 C2664(因为代码尝试将 wchar_t 隐式转换为 unsigned short),则建议更改代码来修正错误,而不是设置 /Zc:wchar_t-。If you upgrade from earlier versions of Visual Studio and encounter compiler error C2664 because the code is trying to implicitly convert a wchar_t to unsigned short, we recommend that you change the code to fix the error, instead of setting /Zc:wchar_t-. 有关详细信息,请参阅 /Zc:wchar_t(wchar_t 是本机类型)For more information, see /Zc:wchar_t (wchar_t Is Native Type).

使用链接器选项 /NODEFAULTLIB、/ENTRY 和 /NOENTRY 升级。Upgrading with the linker options /NODEFAULTLIB, /ENTRY, and /NOENTRY

通过 /NODEFAULTLIB 链接器选项(或“忽略所有默认库”链接器属性),可使链接器不在 CRT 等默认库中自动链接。The /NODEFAULTLIB linker option (or the Ignore All Default Libraries linker property) tells the linker not to automatically link in the default libraries such as the CRT. 这意味着,每个库必须作为输入单独列出。This means that each library has to be listed as input individually. “项目属性”对话框的“链接器”部分中的“附加依赖项”属性中,提供了此库列表。This list of libraries is given in the Additional Dependencies property in the Linker section of the Project Properties dialog.

在升级过程中,使用此选项的项目会出现问题,因为某些默认库的名称已更改。Projects that use this option present a problem when upgrading, because the names of some of the default libraries have changed. 由于每个库都需被列在“附加依赖项”属性或链接器命令行中,因此需要使用当前名称来更新库列表。Because each library has to be listed in the Additional Dependencies property or on the linker command line, you need to update the list of libraries to use the current names.

下表显示自 Studio 2015 开始名称已更改的库。The following table shows the libraries whose names changed starting with Visual Studio 2015. 若要升级,需要将第一列中的名称替换为第二列中的名称。To upgrade, you need to replace the names in the first column with the names in the second column. 其中有些库是导入库,但这应该没有什么影响。Some of these libraries are import libraries, but that shouldn’t matter.

如果你使用的是:If you were using: 需要将其替换为:You need to replace it with:
libcmt.liblibcmt.lib libucrt.lib、libvcruntime.liblibucrt.lib, libvcruntime.lib
libcmtd.liblibcmtd.lib libucrtd.lib、libvcruntimed.liblibucrtd.lib, libvcruntimed.lib
msvcrt.libmsvcrt.lib ucrt.lib、vcruntime.libucrt.lib, vcruntime.lib
msvcrtd.libmsvcrtd.lib ucrtd.lib、vcruntimed.libucrtd.lib, vcruntimed.lib

使用 /ENTRY 选项或 /NOENTRY 选项也会出现此问题,这两个选项也有绕过默认库的效果。The same issue applies also if you use the /ENTRY option or the /NOENTRY option, which also have the effect of bypassing the default libraries.

改进语言符合性带来的错误Errors due to improved language conformance

多年来,Microsoft Visual C++ 编译器一直不断改进针对 C++ 标准的符合性。The Microsoft Visual C++ compiler has continuously improved its conformance to the C++ standard over the years. 在早期版本中编译的代码可能无法在 Visual Studio 2017 中编译,因为编译器会正确标记先前忽略或显式允许的错误。Code that compiled in earlier versions might fail to compile in Visual Studio 2017 because the compiler correctly flags an error that it previously ignored or explicitly allowed.

例如,早期版本的 MSVC 引入了 /Zc:forScope 开关。For example, the /Zc:forScope switch was introduced early in the history of MSVC. 它允许不符合循环变量的行为。It permits non-conforming behavior for loop variables. 现已弃用该开关,并可能在将来版本中将其删除。That switch is now deprecated and might be removed in future versions. 强烈建议不要在升级代码时使用该开关。It is highly recommended to not use that switch when upgrading your code. 有关详细信息,请参阅已弃用 /Zc:forScopeFor more information, see /Zc:forScope- is deprecated.

升级时一个常见的编译器错误是将非常数参数传递到常数参数。One example of a common compiler error you might see when upgrading is when a non-const argument is passed to a const parameter. 旧版本的编译器并不总是将其标记为错误。Older versions of the compiler did not always flag this as an error. 有关详细信息,请参阅编译器的更严格转换For more information, see The compiler's more strict conversions.

有关特定符合性改进的详细信息,请参阅 Visual C++ 更改历史记录 2003 - 2015 以及 Visual Studio 2017 中 C++ 的符合性改进For more information on specific conformance improvements, see Visual C++ change history 2003 - 2015 and C++ conformance improvements in Visual Studio 2017.

涉及 <stdint.h> 整型类型的错误Errors involving <stdint.h> integral types

<stdint.h> 标头定义了 typedef 和宏,它们保证在所有平台上具有指定长度,这与内置整型类型不同。The <stdint.h> header defines typedefs and macros that, unlike built-in integral types, are guaranteed to have a specified length on all platforms. 一些示例包括 uint32_tint64_tSome examples are uint32_t and int64_t. <stdint.h> 标头已添加到 Visual Studio 2010 中。The <stdint.h> header was added in Visual Studio 2010. 编写于 2010 年之前的代码可能为这些类型提供了专用定义,这些定义可能无法总是与 <stdint.h> 定义保持一致。Code that was written before 2010 might have provided private definitions for those types and those definitions might not always be consistent with the <stdint.h> definitions.

如果错误为 C2371 且涉及 stdint 类型,这可能意味着该类型在代码或第三方 lib 文件中的标头中定义。If the error is C2371, and a stdint type is involved, it probably means that the type is defined in a header either in your code or a third-party lib file. 升级时,应消除 <stdint.h> 类型的任何自定义定义,但应先将自定义定义与当前标准定义进行对比,确保不会引入新问题。When upgrading, you should eliminate any custom definitions of <stdint.h> types, but first compare the custom definitions to the current standard definitions to ensure you are not introducing new problems.

可按 F12 转到定义,查看有问题的类型的定义位置。You can press F12 Go to Definition to see where the type in question is defined.

此处可使用 /showIncludes 编译器选项。The /showIncludes compiler option can be useful here. 在项目的“属性页”对话框中,打开“C/C++” > “高级”页,并将“显示包含文件”设置为“是”。In the Property Pages dialog box for your project, open the C/C++ > Advanced page and set Show Includes to Yes. 然后重新生成项目,并在输出窗口中查看 #includes 列表。Then rebuild your project and see the list of #includes in the output window. 每个标头在包含它的标头下都是缩进的。Each header is indented under the header that includes it.

涉及 CRT 函数的错误Errors involving CRT functions

多年来,针对 C 运行时进行了许多更改。Many changes have been made to the C runtime over the years. 已添加函数的许多安全版本,也删除了函数的一些安全版本。Many secure versions of functions have been added, and some have been removed. 此外,如前文所述,Microsoft 的 CRT 实现在 Visual Studio 2015 中重构为新的二进制文件和相关的 .lib 文件。Also, as described earlier in this article, Microsoft’s implementation of the CRT was refactored in Visual Studio 2015 into new binaries and associated .lib files.

如果错误涉及 CRT 函数,请搜索 Visual C++ 更改历史记录(2003 - 2015)Visual Studio 2017 中 C++ 的符合性改进,查阅这些主题中是否包含附加信息。If an error involves a CRT function, search Visual C++ change history 2003 - 2015 or C++ conformance improvements in Visual Studio 2017 to see if those topics contain any additional information. 如果错误为 LNK2019,无法解析的外部对象,请确保未删除函数。If the error is LNK2019, unresolved external, make sure the function has not been removed. 否则,若确定函数仍存在,且调用代码正确,请检查项目是否使用了 /NODEFAULTLIB。Otherwise, if you are sure that the function still exists, and the calling code is correct, check to see whether your project uses /NODEFAULTLIB. 如果是这样,则需更新库列表,以便项目使用新通用 (UCRT) 库。If so you need to update the list of libraries so that the project uses the new universal (UCRT) libraries. 有关详细信息,请参阅有关库和依赖项的上述部分。See the section above on Library and dependencies for more information.

如果错误涉及 printfscanf,请确保未在不包含 stdio.h 的情况下私下定义这两种函数中的任意一种。If the error involves printf or scanf, make sure that you are not privately defining either function without including stdio.h. 如果定义了,请删除私有定义或删除到 legacy_stdio_definitions.lib 的链接。If so, either remove the private definitions or link to legacy_stdio_definitions.lib. 可以在“附加依赖项”属性中的“配置属性” > “链接器” > “输入”下的“属性页”对话框中对此进行设置。You can set this in the Property Pages dialog under Configuration Properties > Linker > Input, in the Additional Dependencies property. 若要使用 Windows SDK 8.1 或更早的版本进行链接,请添加 legacy_stdio_definitions.lib。If you are linking with Windows SDK 8.1 or earlier, then add legacy_stdio_definitions.lib.

如果错误涉及格式字符串参数,这可能是由于编译器在强制执行标准方面更严格。If the error involves format string arguments, this is probably because the compiler is stricter about enforcing the standard. 有关详细信息,请参阅更改历史记录。See the change history for more information. 请密切注意此处的任何错误,因为它们可能表示存在安全风险。Please pay close attention to any errors here because they can potentially represent a security risk.

C++ 标准中的更改导致的错误Errors due to changes in the C++ standard

C++ 标准发展的方式并不总是后向兼容。The C++ standard itself has evolved in ways that are not always backward compatible. 在 C++11 中引入移动语义、新关键字以及其他语言和标准库功能可能导致编译器错误和不同的运行时行为。The introduction in C++11 of move semantics, new keywords, and other language and standard library features can potentially cause compiler errors and even different runtime behavior.

例如,旧 C++ 程序可能包含 iostream.h 标头。For example, an old C++ program might include the iostream.h header. 此标头已在早期版本的 C++ 中弃用,且最终从 Visual Studio 中彻底删除。This header was deprecated early in the history of C++ and was eventually removed completely from Visual Studio. 在此情况下,需使用 <iostream>,并重写代码。In this case, you will need to use <iostream> and rewrite your code. 有关详细信息,请参阅更新旧的 iostreams 代码For more information, see Updating old iostreams code.

C4838:收缩转换警告C4838: narrowing conversion warning

目前根据 C++ 标准,将无符号整型值转换为带符号整型值视为收缩转换。The C++ standard now specifies that conversions from unsigned to signed integral values are considered as narrowing conversions. 在 Visual Studio 2015 之前,编译器不会发出此警告。The compiler did not raise this warning prior to Visual Studio 2015. 应检查每个事件,以确保收缩不会影响代码的正确性。You should inspect each occurrence to make sure the narrowing does not impact the correctness of your code.

使用安全 CRT 函数的警告Warnings to use secure CRT functions

多年来,已引入 C 运行时函数的多个安全版本。Over the years, secure versions of C runtime functions have been introduced. 尽管不安全的旧版本仍然可用,但建议更改代码以使用安全版本。Although the old, non-secure versions are still available, it is recommended to change your code to use the secure versions. 编译器将对使用不安全版本的行为发出警告。The compiler will issue a warning for usage of the non-secure versions. 可选择禁用或忽略这些警告。You can choose to disable or ignore these warnings. 要为解决方案中的所有项目禁用警告,请打开“视图” > “属性管理器”,选择要禁用警告的所有项目,然后右键单击所选项,并选择“属性”。To disable the warning for all projects in your solution, open View > Property Manager, select all projects for which you want to disable the warning, then right-click on the selected items and choose Properties. 在“配置属性” > “C/C++” > “高级”下的“属性页”中,选择“禁用特定警告”。In the Property Pages dialog under Configuration Properties > C/C++ > Advanced, select Disable Specific Warnings. 单击下拉箭头,然后单击“编辑”。Click the drop-down arrow and then click on Edit. 在文本框中输入 4996。Enter 4996 into the text box. (请勿包括“C”前缀。)有关详细信息,请参阅移植以使用安全 CRT(Don't include the 'C' prefix.) For more information, see Porting to use the Secure CRT.

对 Windows API 或已过时 SDK 进行的更改所导致的错误Errors due to changes in Windows APIs or obsolete SDKs

多年来,已添加若干 Windows API 和数据类型,有时还会对其进行更改或删除。Over the years, Windows APIs and data types have been added, and sometimes changed or removed. 此外,不属于核心操作系统的其他 SDK 也是添了又删。Also, other SDKs that did not belong to the core operating system have come and gone. 因此,较旧的程序可能包含对已不存在的 API 的调用。Older programs may therefore contain calls to APIs that no longer exist. 它们还可能包含对已不受支持的其它 Microsoft SDK 中 API 的调用。They may also contain calls to APIs in other Microsoft SDKs that are no longer supported. 如果错误涉及 Windows API 或较旧 Microsoft SDK 中的 API,则 API 可能已删除且/或已被更新、更安全的函数取代。If you see an error involving a Windows API or an API from an older Microsoft SDK, it is possible that an API has been removed and/or superseded by a newer, more secure function.

若要深入了解当前 API 设置以及特定 Windows API 支持的操作系统最低版本,请参阅 Microsoft API 和参考目录,并导航至出现问题的 API。For more information about the current API set and the minimum supported operating systems for a specific Windows API, see Microsoft API and reference catalog and navigate to the API in question.

Windows 版本Windows version

在升级直接或间接使用 Windows API 的程序时,需要决定要支持的 Windows 最低版本。When upgrading a program that uses the Windows API either directly or indirectly, you will need to decide the minimum Windows version to support. 在大多数情况下,Windows 7 是一个不错的选择。In most cases Windows 7 is a good choice. 有关详细信息,请参阅头文件问题For more information see Header file problems. WINVER 宏定义设计用于运行程序的 Windows 旧版本。The WINVER macro defines the oldest version of Windows that your program is designed to run on. 若 MFC 程序将 WINVER 设置为 0x0501 (Windows XP),用户将收到警告,因为虽然编译器本身具有 XP 模式,但 MFC 已不再支持 XP。If your MFC program sets WINVER to 0x0501 (Windows XP) you will get a warning because MFC no longer supports XP, even though the compiler itself has an XP mode.

有关详细信息,请参阅更新目标 Windows 版本更多过时的头文件For more information, see Updating the Target Windows Version and More outdated header files.


ATL 和 MFC 是相对稳定的 API,但偶尔对其进行更改。ATL and MFC are relatively stable APIs but changes are made occasionally. 有关详细信息,请参阅 Visual C++ 更改历史记录 2003 - 2015Visual Studio 2017 中 Visual C++ 的新增功能以及Visual Studio 2017 中 C++ 的符合性改进See the Visual C++ change history 2003 - 2015 for more information and What's New for Visual C++ in Visual Studio 2017 and C++ conformance improvements in Visual Studio 2017.

已在 MSVCRTD.lib 中定义 LNK 2005 _DllMain@12LNK 2005 _DllMain@12 already defined in MSVCRTD.lib

MFC 应用程序中可能发生此错误。This error can occur in MFC applications. 它指示 CRT 库和 MFC 库之间的顺序问题。It indicates an ordering issue between the CRT library and the MFC library. 需要先链接 MFC,使其提供 new 和 delete 运算符。MFC needs to be linked first so that it provides new and delete operators. 要修复此错误,请使用 /NODEFAULTLIB 开关来忽略以下默认库:MSVCRTD.lib 和 mfcs140d.lib。To fix the error, use the /NODEFAULTLIB switch to Ignore these default libraries: MSVCRTD.lib and mfcs140d.lib. 然后将这些相同的 lib 添加为附加依赖项。Then add these same libs as additional dependencies.

32 位和 64 位32 vs 64 bit

如果原始代码针对 32 位系统编译,除了新建 32 位应用外,还可以选择创建 64 位版本。If your original code is compiled for 32-bit systems, you have the option of creating a 64-bit version instead of or in addition to a new 32-bit app. 一般情况下,应首先在 32 位模式下编译程序,然后再尝试使用 64 位模式。In general, you should get your program compiling in 32-bit mode first, and then attempt 64-bit. 针对 64 位进行编译是直截了当的方法,但在某些情况下,这可能暴露出 32 位版本中隐藏的一些 Bug。Compiling for 64-bit is straightforward, but in some cases it can reveal bugs that were hidden by 32-bit builds.

此外,还应注意可能的编译时和运行时问题,这些问题与 printf 和 scanf 函数中的指针大小、时间和大小值以及格式说明符相关。Also, you should be aware of possible compile-time and runtime issues relating to pointer size, time and size values, and format specifiers in printf and scanf functions. 有关详细信息,请参阅针对 64 位 x64 目标配置 Visual C++Visual C++ 64 位迁移的常见问题For more information, see Configure Visual C++ for 64-bit, x64 targets and Common Visual C++ 64-bit Migration Issues. 有关迁移的其他提示,请参阅适用于 64 位 Windows 的编程指南For additional migration tips, see Programming Guide for 64-bit Windows.

Unicode 和 MBCS/ASCIIUnicode vs MBCS/ASCII

在标准化 Unicode 之前,许多程序使用多字节字符集 (MBCS) 来表示未包含在 ASCII 字符集中的字符。Before Unicode was standardized, many programs used the Multibyte Character Set (MBCS) to represent characters that were not included in the ASCII character set. 在较早的 MFC 项目中,MBCS 是默认设置,在升级此类程序时,你将收到建议使用 Unicode 的警告。In older MFC projects, MBCS was the default setting, and when you upgrade such a program, you will see warnings that advise to use Unicode instead. 如果你认为考虑到开发成本,不值得转换至 Unicode,则可以选择禁用或忽略此警告。You may choose to disable or ignore the warning if you decide that converting to Unicode is not worth the development cost. 要为解决方案中的所有项目禁用警告,请打开“视图” > “属性管理器”,选择要禁用警告的所有项目,然后右键单击所选项,并选择“属性”。To disable it for all projects in your solution, open View > Property Manager, select all projects for which you want to disable the warning, then right-click on the selected items and choose Properties. 在“属性页”对话框中,选择“配置属性” > “C/C++” > “高级”。In the Property Pages dialog, select Configuration Properties > C/C++ > Advanced. 在“禁用特定警告”属性中展开下拉箭头,然后选择“编辑”。In the Disable Specific Warnings property, open the drop-down arrow and then choose Edit. 在文本框中输入 4996。Enter 4996 into the text box. (请勿包括“C”前缀。)选择“确定”保存该属性,然后选择“确定”保存所做更改。(Don't include the 'C' prefix.) Choose OK to save the property, then choose OK to save your changes.

有关详细信息,请参阅从 MBCS 移植到 UnicodeFor more information, see Porting from MBCS to Unicode. 有关 MBCS 和 Unicode 的常规信息,请参阅 Visual C++ 中的文本和字符串,以及国际化For general information about MBCS vs. Unicode, see Text and Strings in Visual C++ and Internationalization .

请参阅See also

从 Visual C++ 早期版本升级项目Upgrading Projects from Earlier Versions of Visual C++
Visual Studio 2017 中 C++ 的符合性改进C++ conformance improvements in Visual Studio 2017