原始的C运行时库从来没有想过必须支持从多个模块构建的程序。它包含全局变量,如errno
和stdout
以及具有隐式全局状态的函数,如strtok()
和malloc()
。您可以将DLL与他们自己的CRT副本链接起来,但这对设计DLL接口的方式提出了相当苛刻的要求。你必须非常小心地对从不依赖于CRT状态。获得这个错误几乎不可能诊断运行时错误行为。
对此的解决方法是在您的过程中只有一个一个 CRT副本。这是/ MD完成的,你最终会依赖于存储在DLL中的CRT版本。由所有模块共享。像msvcr120.dll一样,由VS2013使用。
编译器需要知道这个,以便它可以正确使用该DLL版本。一个简单的例子是errno
,它是一个带有/ MT的全局变量,但是被宏编辑为带有/ MD的函数调用,因此只有DLL中的一个全局用于跟踪最后一个已知值。如果在编译器的.h文件中使用/ MD,则将定义_DLL
宏。
另外一个副作用是编译器自动为msvcrt.lib或libcmt.lib插入链接指令(相当于#pragma注释)。旨在帮助您避免错误,并省略明确指定CRT库链接指令的需求。如果出现错误,则很难诊断链接器错误消息。与您尝试链接.obj或。时获得的种类不同。lib文件与/ MT和/ MD不匹配。哪一个当然不能正常工作,你不能对两者都有依赖性。
中的.libs都不是导入库
你的名字,ole32.lib,advapi32.lib,USER32.LIB列出的那些,其实都是导入库。它们是标准的操作系统DLL。在运行时,程序将加载相应的DLL,从调试器中可以很容易看到。对于VS,你会在输出窗口中看到它。值得注意的是,这些DLL实际上使用了与您的程序不同的CRT,它们绑定到c:\ windows \ system32 \ msvcrt.dll。 winapi经过精心设计,永远不会造成这个问题。
做链接使用静态或动态链接默认
没有默认值,它取决于你链接的.lib。区分静态链接库和导入库。导入库是在构建DLL时创建的。它是一个不包含代码的小文件,只是DLL中导出函数的名称,因此链接器知道将条目放入程序的导入表中。当程序启动时,DLL依赖项被解析并且导入的函数被加载器绑定。