【问题标题】:Use case of dllimport in VisualStudioVisual Studio中dllimport的用例
【发布时间】:2014-07-10 07:43:45
【问题描述】:

我一直想知道__declspec(dllimport) 的真正用例是什么。我知道构建共享库需要使用__declspec(dllexport) 导出其符号,然后库的用户将这些符号用作__declspec(dllimport)

然后,您应该使用启用dllexport 的特殊定义来构建共享库,如果未设置标志,则符号定义为dllimport

但是,我从来没有使用过dllimport,它确实有效。

我有两个项目:

导入导出

有一个使用 EXPORTING 定义构建的小型 Util 类

Util.h:

#ifndef _UTIL_H_
#define _UTIL_H_

#if defined(EXPORTING)
#  define EXPORT    __declspec(dllexport)
#else
#  define EXPORT    // I should use __declspec(dllimport) but client will try out
#endif

class EXPORT Util {
public:
    static void test();
};

#endif // !_UTIL_H_

然后在源文件Util.cpp中:

#include <iostream>

#include "Util.h"

void Util::test()
{
    std::cout << "Testing..." << std::endl;
}

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

客户端 exe

Main.cpp:

#include <Util.h>

int main(void)
{
    Util::test();

    return 0;
}

链接到 ImportExport.lib 没有任何定义集,正常工作。没有未定义的引用。

我想知道为什么是dllimport的用例?它存在是为了向后兼容吗?

注意:所有代码都在 VisualStudio 2012 Express 上测试过。

【问题讨论】:

标签: c++ visual-c++ linker


【解决方案1】:

Raymond Chen在this series中详细描述了dll导入机制;总结一下,函数dllimport本质上是一种性能优化。

如果您没有将函数标记为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;对于数据,它始终是必要的,因为链接器没有可用的机制来重新处理对编译器在间接变量中生成的变量的直接访问。

(所有这些在“经典”链接器时代尤为重要;如今,启用链接时代码生成后,只需让链接器完全生成函数调用/数据访问即可解决所有这些问题)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 2014-10-04
    • 2018-04-15
    相关资源
    最近更新 更多