use*_*967 5 c++ crt visual-studio-2013
我正在尝试更好地掌握Visual Studio 2013中的CRT库选项(C++ - >代码生成 - >运行时库)以及如何知道选择哪个选项(以及何时更改默认值).
来自MSDN:
可重用库及其所有用户应使用相同的CRT库类型,因此使用相同的编译器开关.
因此,我的理解是,如果您要链接第三方库,则应使用与构建库相同的CRT版本.构建库的人应该指定构建中使用的CRT选项.
有没有办法通过查看.lib文件来确定使用哪个CRT版本?
更重要的是,如果您没有链接任何第三方库,您将如何决定使用哪个选项?您何时考虑更改默认值?
简短回答:
因此,我的理解是,如果您要链接第三方库,则应使用与构建库相同的CRT版本.构建库的人应该指定构建中使用的CRT选项.
这是最容易出错的选项.可以混合运行时,但如果这样做,可能会遇到意外的错误.
有没有办法通过查看.lib文件来确定使用哪个CRT版本?
我不知道.lib
它本身,但如果第三方代码有DLL或EXE,你可以看到它依赖于使用Windows Dependency Walker工具的CRT DLL .
如果它是一个静态库,并且您的代码的CRT选择不匹配,那么在构建时您将看到警告.
更重要的是,如果您没有链接任何第三方库,您将如何决定使用哪个选项?您何时考虑更改默认值?
对于最简单的部署,静态链接是最好的; 你可以自己运送可执行文件,它将运行.对于具有多个EXE和DLL的较大项目,如果静态链接,则代码大小会更大.如果在同一进程中有多个模块(EXE加上1个或更多自己的DLL),那么最好共享相同的CRT代码.
更多细节(基于我之前写的博客文章):
您可以使用以下四种C/C++运行时库变体来构建代码:
通过在Visual Studio中右键单击项目并选择"属性",在弹出的对话框中单击" C/C++"下的"代码生成"选项,然后转到" 运行时库"属性,可以选择要使用的库.
请记住,此设置是按配置进行的,因为您需要为Debug配置选择Debug运行时库,为Release配置选择Release运行时库.
有什么不同?
该DLL运行时库选项意味着您动态链接针对C/C++运行时,对你的程序运行,该DLL将需要的地方你的程序可以找到它(稍后更多).
不提及DLL(多线程调试和多线程发布)的选项会导致程序与运行时静态链接.这意味着您不需要外部DLL来运行程序,但是由于额外的代码,您的程序会更大,并且还有其他原因可能您不想选择它.
默认情况下,在Visual Studio中创建新项目时,它将使用DLL运行时.
运行时名称中的多线程是过去非线程安全和多线程C/C++运行时的遗留问题.即使您自己的应用程序是单线程的,您也将始终使用现代Visual Studio 的多线程运行时.
如果您要链接DLL运行时,那么在发布程序(测试和客户)时,您将不得不考虑如何部署它们.
如果将Debug版本提供给测试团队,请确保同时提供DLL运行时的Debug变体.
此外,不要忘记获得正确的架构(例如x86 vs x64).
Microsoft提供可再发行的软件包来安装Release(但不是Debug)DLL.通过搜索Visual C++ Redistributable 2013(取代Visual Studio版本以满足您的需求),可以轻松找到这些内容.您还可以直接访问Microsoft网站上的最新支持的Visual C++下载.
这些可再发行组件包是可执行文件,您可以从程序的安装程序中调用它们(或者您可以手动运行它们以设置测试环境).请注意,x86和x64有单独的可再发行组件.
如果您正在构建MSI安装程序,则可以将正在使用的C/C++运行时的合并模块合并到安装程序包中.这些合并模块通常位于C:\Program Files (x86)\Common Files\Merge Modules
.例如,调用x86 C/C++运行时的Visual Studio 2013合并模块Microsoft_VC120_CRT_x86.msm
.
请注意,这些合并模块名称中的版本号不是基于年份的产品版本,而是内部版本号.维基百科上的这个表显示了版本号之间的映射,以避免混淆.
与上面的独立可执行可再发行安装程序不同,合并模块也有Debug变体.
某些版本的Visual Studio支持Visual Studio Installer项目类型(在" 其他项目类型"中的" 设置和部署"类别下),如果您在其中一个安装程序中包含程序项目的输出,则运行时的合并模块将为自动包含.您也可以使用它作为获取安装程序的技巧,该安装程序将安装Debug运行时以进行内部测试(任何虚拟C/C++项目都可以,它不必实际安装您的程序).
您也可以将DLL从Visual C++安装中的redist文件夹复制到安装程序的位置.例如,对于Visual Studio 2013,您可以在某处找到x64 C/C++运行时库C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x64\Microsoft.VC120.CRT\
.
可以在某处找到调试变体C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\Debug_NonRedist
.
(根据Visual Studio版本和安装位置调整路径).
在理想的世界中,对于链接到程序中的所有库,您将使用相同的C/C++运行时库变体(Debug vs Release,DLL vs 静态链接),以及来自相同版本的Visual Studio的所有变体.
如果你混合运行时,你可能会遇到链接器错误,你的程序可能根本无法运行,或者更糟糕的是,它可能似乎工作但崩溃或仅在某些情况下给出错误的结果.
一个常见的情况是您只拥有某些第三方库的Release版本,但您仍然希望能够使用此库构建自己代码的Debug变体.另一种情况是,您有一个使用静态C/C++运行时的库,并且您希望在程序中使用DLL版本,反之亦然.
如果第三方库是C代码,那么您可能能够使用/NODEFAULTLIB
链接器选项逃脱这一点,并让它实际工作.
如果库是C++代码,那么您可能运气不好,因为生成的代码太多与特定运行时中的符号相关联.
这些是不同的库名称:
请记住,您要忽略的运行时库是第三方代码正在使用的运行时库,即它将与您自己的程序正在使用的库不同.如果你看看你的构建输出,你会被提示选择正确的构建输出,例如:
LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library
您可以通过右键单击项目,选择" 属性",单击" 链接器"下的" 输入"条目并将运行时库名称添加到条目中来指定要忽略的库.
您还可以跨模块边界以更微妙的方式遇到C/C++运行时不匹配问题(例如,在EXE和它加载的DLL之间).
例如,可以通过不同的运行时间来不同地定义C库中的数据结构.我已经看到这种原因在使用DLL的程序中崩溃,这些DLL FILE*
在其API中使用了a .使用一个C运行时在一个模块中打开文件,并与另一个具有不同,不兼容的实现的模块进行交互.更安全的选项包括HANDLE
为这样的事情传递Windows API 对象,或者以与运行时无关的方式包装文件交互.
不同的运行时也使用自己的内存堆进行分配.如果一个对象在一个堆上的一个模块中分配,但在另一个模块中解除分配,则如果C/C++运行时不匹配,则可能发生崩溃.这当然仅适用于使用C或C++运行时的分配,例如malloc
或new
.例如,如果在任何地方都使用默认的Windows进程堆,那么一切都很好.
请注意,如果模块静态链接到C/C++运行时,即使它们与它们链接的运行时的变体相同,它们也会遇到此问题,因为仍然会有两个不同的运行时,其中有自己的内存堆.因此,您将需要在这种情况下使用DLL C/C++运行时.
如果运行时实现的功能(例如带有vtable的异常或类)跨越模块边界,那么在每个模块中使用(相同版本)DLL运行时也是明智的,尽管某些不匹配的组合可能在实践中起作用.