c++ VisualStudio中dllimport的使用案例

qvk1mo1f  于 2024-01-09  发布在  其他
关注(0)|答案(1)|浏览(153)

我一直想知道__declspec(dllimport)的真实的用例是什么。我知道构建一个共享库需要使用__declspec(dllexport)导出它的符号,然后库的用户使用这些符号作为__declspec(dllimport)
然后,您应该使用启用dllexport的特殊定义来构建共享库,如果未设置标志,则将符号定义为dllimport
然而,我从来没有使用过dllimport在所有和它只是工作。
我有两个项目:

进出口

有一个小的Util类,它是用定义的EXPORTING构建的
使用时间:

  1. #ifndef _UTIL_H_
  2. #define _UTIL_H_
  3. #if defined(EXPORTING)
  4. # define EXPORT __declspec(dllexport)
  5. #else
  6. # define EXPORT // I should use __declspec(dllimport) but client will try out
  7. #endif
  8. class EXPORT Util {
  9. public:
  10. static void test();
  11. };
  12. #endif // !_UTIL_H_

字符串
然后在源文件Util.cpp中:

  1. #include <iostream>
  2. #include "Util.h"
  3. void Util::test()
  4. {
  5. std::cout << "Testing..." << std::endl;
  6. }


没什么复杂的,正如你所看到的,当用户使用这个文件时,EXPORT根本不会被定义(应该定义为dllimport)。

客户端exe

Main.cpp:

  1. #include <Util.h>
  2. int main(void)
  3. {
  4. Util::test();
  5. return 0;
  6. }


链接到ImportExport.lib而不需要任何定义集,就可以正常工作。没有未定义的引用。
我想知道为什么dllimport的用例?它是为了向后兼容而存在的吗?
注意:所有代码都在VisualStudio 2012 Express上进行了测试。

kb5ga3dv

kb5ga3dv1#

Raymond Chen在this series中详细描述了dll导入机制;总结起来,dllimport for functions本质上是一种性能优化。
如果你没有将一个函数标记为dllimport,编译器和链接器will treat it as a normal function,使用“静态”函数调用将其解析为导入库中的存根。存根实际上必须从IAT获取导入函数的地址,并在那里执行jmp。(即,它必须以某种方式将编译器生成的直接调用转换为间接调用),因此在这个两步过程中会有一些性能损失。
相反,dllimport从编译阶段就通过IAT告诉编译器it has to generate code for an indirect call。这减少了间接性,并允许编译器缓存(本地到函数)目标函数地址。
注意,as MSDN says,你可以只在函数中省略dllimport;对于数据,它总是必要的,因为没有一种机制可供链接器修改对编译器生成的变量的直接访问。
(all这在“经典”链接器的时代尤其重要;如今,启用了链接时代码生成,所有这些问题都可以通过简单地让链接器完全生成函数调用/数据访问来解决)

相关问题