gpt4 book ai didi

c++ - CRT库类型

转载 作者:行者123 更新时间:2023-12-01 18:54:35 26 4
gpt4 key购买 nike

我试图更好地了解Visual Studio 2013中的CRT库选项(C++->代码生成->运行时库)以及如何知道选择哪个选项(以及何时更改默认值)。

MSDN:

A reusable library and all of its users should use the same CRT library types and therefore the same compiler switch.



因此,我的理解是,如果要链接到第三方库,则应使用与构建该库相同的CRT版本。谁构建了库,都应指定在构建中使用了什么CRT选项。

是否可以仅通过查看.lib文件来确定使用哪个CRT版本?

更重要的是,如果不与任何第三方库链接,您将如何决定使用哪个选项?您何时考虑更改默认值?

最佳答案

简短回答:

So, my understanding is that if you are linking with a third party library, you should use the same CRT version that was used to build the library. Whoever built the library should specify what CRT option was used in the build.



那是最不容易出错的选项。可以混合运行时,但是如果这样做,则可能会遇到意外错误。

Is there a way to determine which CRT version was used just by looking at the .lib file?



我不知道 .lib本身,但是如果第三方代码具有DLL或EXE,则可以使用Windows Dependency Walker工具查看它依赖于什么CRT DLL。

如果它是静态库,并且代码的CRT选择不匹配,则在构建时会看到警告。

More importantly, how would you decide which option to use if you aren't linking with any third-party libraries? When would you consider changing the default?



对于最简单的部署,静态链接是最好的。您可以单独发送可执行文件,它将运行。对于较大的项目,其中有多个EXE和DLL,如果您进行静态链接,则代码大小将更大。如果在同一进程中有多个模块(EXE加1个或更多自己的DLL),则最好共享相同的CRT代码。

详细信息(基于我之前写的博客文章):

库变体

您可以根据以下四种构建C/C++运行时库的代码:
  • 多线程调试DLL
  • 多线程DLL
  • 多线程调试
  • 多线程

  • 通过右键单击Visual Studio中的项目并选择“属性”,然后在弹出的对话框中的 C/C++ 下单击 代码生成选项,然后转到 运行时库,可以选择要使用的库。 属性。

    请记住,此设置是针对每个配置的,因为您需要为 调试配置选择 调试运行时库,为 发行配置选择 发布运行时库。

    有什么不同?

    DLL 运行时库选项意味着您可以针对C/C++运行时动态链接,并且要使程序运行, DLL 将需要在程序可以找到它的位置(稍后会详细介绍)。

    不提及DLL的选项( 多线程调试多线程发行版)会导致您的程序针对运行时进行静态链接。这意味着您不需要外部DLL即可运行该程序,但是由于额外的代码,您的程序会更大,并且还有其他原因可能导致您不希望选择它。

    默认情况下,当您在Visual Studio中创建新项目时,它将使用 DLL 运行时。

    运行时名称中的多线程是以前使用非线程安全和多线程C/C++运行时的遗产。即使您自己的应用程序是单线程的,您也将始终在现代Visual Studio中使用多线程运行时。

    部署DLL运行时

    如果要针对DLL运行时进行链接,则必须考虑在发布程序(测试和客户)时如何部署它们。

    如果将 调试交付给测试团队,请确保也提供DLL运行时的Debug变体。

    另外,不要忘记获得正确的架构(例如 x86 x64 )。

    可再发行安装程序

    Microsoft提供了可重新分发的程序包,它们安装了版本(但未安装调试)DLL。通过搜索(类似于Visual C++ Redistributable 2013 )(将Visual Studio版本替换为您所需的东西),可以很容易地找到它们。您也可以直接在Microsoft网站上转到Latest Supported Visual C++ Downloads

    这些可重新分发的软件包是可执行文件,您可以从程序的安装程序中调用它们(也可以手动运行它们以设置测试环境)。请注意,x86和x64有单独的可再发行组件。

    合并模块

    如果您要构建MSI安装程序,则可以将正在使用的C/C++运行时的Merge Module合并到安装程序包中。这些合并模块通常在C:\Program Files (x86)\Common Files\Merge Modules中找到。例如,用于Visual Studio 2013的x86 C/C++运行时的合并模块称为Microsoft_VC120_CRT_x86.msm

    请注意,这些合并模块名称中的版本号不是基于年份的产品版本,而是内部版本号。 This table on Wikipedia显示版本号之间的映射,以避免混淆。

    与上述独立的可执行文件可再发行安装程序不同,合并模块还具有Debug变体。

    某些版本的Visual Studio支持 Visual Studio Installer 项目类型(在其他项目类型中的安装和部署类别下),并且如果您将程序项目的输出包括在这些安装程序之一中,则运行时的合并模块将自动包括在内。您也可以以此作为技巧,以获取将安装调试运行时以进行内部测试的安装程序(任何虚拟C/C++项目都可以,不需要实际安装程序)。

    从Redist文件夹复制

    您也可以将DLL从Visual C++安装中的redist文件夹复制到安装程序的位置。例如,对于Visual Studio 2013,您会在C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x64\Microsoft.VC120.CRT\之类的地方找到x64 C/C++运行时库。

    调试变体可以在C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\Debug_NonRedist之类的地方找到。

    (根据您的Visual Studio版本和安装位置调整路径)。

    混合C/C++运行时

    在理想情况下,您将使用相同的C/C++运行时库变体(调试版本 DLL 静态链接的),以及所有来自相同Visual Studio版本的所有库链接到您的程序。

    如果混合运行时,则可能会出现链接器错误,程序可能根本无法运行,或者更糟的是,它似乎正在运行,但仅在某些情况下崩溃或给出错误的结果。

    忽略默认库

    一种常见的情况是,您仅具有某些第三方库的版本版本,但是您仍然希望能够使用此库构建自己代码的调试变体。另一种情况是,您有一个使用静态C/C++运行时的库,并且想要程序中的 DLL 版本,或者相反。

    如果第三方库是C代码,那么您可以使用 /NODEFAULTLIB linker option摆脱它并使其真正起作用。

    如果该库是C++代码,您可能会很走运,因为在特定的运行时中,太多的生成代码都与符号绑定(bind)在一起。

    这些是不同的库名称:
  • LIBCMT.LIB :静态链接的发行版运行时(也称为多线程)
  • LIBCMTD.LIB :静态链接的调试运行时(也称为多线程调试)
  • MSVCRT.LIB :动态链接的发行版运行时(也称为多线程DL L)
  • MSVCRTD.LIB :动态链接的调试运行时(也称为多线程调试DLL )

  • 请记住,您要忽略的运行时库是第三方代码使用的库,即它将与您自己的程序使用的库不同。如果您查看构建输出,则系统将提示您选择正确的输出,例如:
    LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library
    您可以通过右键单击项目,选择属性,单击链接器下的输入条目,然后将运行时库名称添加到该条目中,来指定要忽略的库。

    跨越模块边界

    您还可以跨模块边界(例如在EXE和它加载的DLL之间)以更微妙的方式遇到C/C++运行时不匹配问题。

    例如,C库中的数据结构可以通过不同的运行时来不同地定义。我已经看到这会导致使用DLL的程序崩溃,该DLL在其API中使用了FILE*。使用一个C运行时在一个模块中打开文件,并通过具有不同的不兼容实现的另一个模块与文件进行交互。更安全的选择包括为此类事情传递Windows API HANDLE对象,或者以与运行时无关的方式包装文件交互。

    不同的运行时也使用它们自己的内存堆进行分配。如果将一个对象分配到一个堆上的一个模块中,但又释放给另一个模块,则如果C/C++运行时不匹配,则很可能发生崩溃。当然,这仅适用于使用C或C++运行时的分配,例如mallocnew。例如,如果在各处都使用默认的Windows进程堆,那么一切都很好。

    请注意,如果模块静态链接到C/C++运行时,即使它们是链接到的运行时的变体,它们也会遇到此问题,因为仍然会有两个不同的运行时,它们在使用自己的内存堆。因此,在这种情况下,您将需要使用DLL C/C++运行时。

    如果运行时实现的功能(例如带有vtable的异常或类)在运行时实现的功能跨越了模块边界,则在每个模块中使用DLL运行时(相同版本)也是明智的,尽管实际上某些不匹配的组合可能会起作用。

    关于c++ - CRT库类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29462439/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com