_declspec(dllimport)请问为什么C++里面生成dll,如果接口用import定义,最后生成的dll里面还是会找到该函数符号

_declspec(dllimport)
请问为什么C++里面生成dll,如果接口用import定义,最后生成的dll里面还是会找到该函数符号?,这个不应该是导入才有的吗

__declspec(dllimport)__declspec(dllexport)是Microsoft Visual C++编译器使用的特定关键字,用于在DLL(动态链接库)和使用这些库的代码之间设置链接规格。

在一般的应用中,这两个关键字是如何工作的呢?

  1. 当你在创建一个DLL时,你会使用__declspec(dllexport)来标记你想要公开的函数、变量或者对象。这样,编译器就知道这些符号需要被导出,而不是仅在DLL内部使用。

  2. 在另一边,你使用DLL的代码应该使用__declspec(dllimport)来标记那些在DLL中定义的函数、变量或者对象。这告诉编译器这些符号实际上是在别处定义的,编译器将生成正确的代码来从DLL中调用或访问这些符号。

现在,关于你的问题——即使你用__declspec(dllimport)标记了一个符号,但在最终的DLL中仍然能找到该符号。这是因为__declspec(dllimport)只是告诉编译器这个符号是在别处定义的,但并不阻止你在当前的DLL中重新定义或者实现它。如果你在编译DLL的代码中实际实现了这个符号,那么它仍然会出现在最终的DLL中。

如果你不希望这个符号出现在最终的DLL中,你需要确保在编译DLL的代码中没有实现它,而只是在头文件中声明它,并使用__declspec(dllimport)进行标记。

  • 这篇博客: C/C++相关的文件、__declspec(dllexport)、__declspec(dllimport)中的 一些其他问题 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    1. __declspec(dllexport)和__declspec(dllimport)
      这是修饰语句,用来说明函数是导出函数或导入函数
      __declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。但是,MSDN文档里面,对于__declspec(dllimport)的说明让人感觉有点奇怪,先来看看MSDN里面是怎么说的:
      不使用 __declspec(dllimport) 也能正确编译代码,但使用 __declspec(dllimport) 使编译器可以生成更好的代码。
      编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于 DLL 中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨 DLL 边界的函数调用中。
      但是,若想使用DLL 中使用的变量,则必须使用 __declspec(dllimport) 声明才行。
    那我就来试验一下,假定,你在DLL里只导出一个简单的类
    注意,假定你已经在项目属性中定义了SIMPLEDLL_EXPORT
    ///SimpleDLLClass.h
    #ifdef SIMPLEDLL_EXPORT
    #define DLL_EXPORT __declspec(dllexport)
    #else
    #define DLL_EXPORT
    #endif
    
    class DLL_EXPORT SimpleDLLClass
    {
    public:
    SimpleDLLClass();
    virtual ~SimpleDLLClass();
    virtual getValue() { return m_nValue;};
    private:
    int m_nValue;
    };
    
    ///SimpleDLLClass.cpp
    #include "SimpleDLLClass.h"
    SimpleDLLClass::SimpleDLLClass()
    {
    m_nValue=0;
    }
    SimpleDLLClass::~SimpleDLLClass()
    {
    }
    然后你在使用这个DLL中的类,在你的cpp中,没有定义SIMPLEDLL_EXPORT
    所以此时对于cpp来说,.h中就相当于class SimpleDLLClass{};
    这正好对应MSDN上说的__declspec(dllimport)定义与否都可以正常使用。
    

    修改上述代码,将m_nValue改为static变量:

    ///SimpleDLLClass.h
    #ifdef SIMPLEDLL_EXPORT
    #define DLL_EXPORT __declspec(dllexport)
    #else
    #define DLL_EXPORT 
    #endif
    
    class DLL_EXPORT SimpleDLLClass
    {
    public:
    SimpleDLLClass();
    virtual ~SimpleDLLClass();
    virtual getValue() { return m_nValue;};
    private:
    DLL_EXPORT static int m_nValue;
    };
    
    ///SimpleDLLClass.cpp
    #include "SimpleDLLClass.h"
    SimpleDLLClass::SimpleDLLClass()
    {
    static m_nValue=0;
    }
    SimpleDLLClass::~SimpleDLLClass()
    {
    }
    int SimpleDLLClass::m_nValue=0;
    改完之后,再去LINK一下,这时会发现,结果是LINK告诉你找不到这个m_nValue。
    正好对应MSDN上说的若想使用DLL 中使用的静态变量,则必须使用 __declspec(dllimport) 声明才行。
    

    所以需要将代码改为:

    ///SimpleDLLClass.h
    #ifdef SIMPLEDLL_EXPORT
    #define DLL_EXPORT __declspec(dllexport)
    #else
    #define DLL_EXPORT __declspec(dllimport)
    #endif
    原来dllimport是为了更好的处理类中的静态成员变量的
    如果没有静态成员变量,那么这个__declspec(dllimport)无所谓。
    

    总结一下:对于.h文件,定义了SIMPLEDLL_EXPORT,其内部的DLL_EXPORT__declspec(dllexport),对于cpp没有定义SIMPLEDLL_EXPORT,所以在没有修改时,没有DLL_EXPORT没有定义,而修改成static变量后,DLL_EXPORT__declspec(dllimport)

    _declspec(dllexport)与_declspec(dllimport)都是DLL内的关键字,即导出与导入。他们是将DLL内部的类与函数以及数据导出与导入时使用的。主要区别在于,dllexport是在这些类、函数以 及数据的申明的时候使用。用过表明这些东西可以被外部函数使用,即(dllexport)是把DLL中的相关代码(类,函数,数据)暴露出来为其他应用程 序使用。使用了(dllexport)关键字,相当于声明了紧接在(dllexport)关键字后面的相关内容是可以为其他程序使用的。而 dllimport关键字是在外部程序需要使用DLL内相关内容时使用的关键字。当一个外部程序要使用DLL内部代码(类,函数,全局变量)时,只需要在程序内部使用(dllimport)关键字声明需要使用的代码就可以了,即(dllimport)关键字是在外部程序需要使用DLL内部相关内容的时候才 使用。(dllimport)作用是把DLL中的相关代码插入到应用程序中。

    1. 导出函数:dll里的函数或类或数据成员(类和数据成员的应用下面再说)不同于一般的文件,导出函数就是说这个函数可供应用程序调用,
      而没有这个修饰语句的函数就是非导出函数,它只能在dll的内部被调用,而不能被应用程序调用。类似于public和private修饰的那样。
    __declspec(dllexport) int add(int a, int b)
    {
    return a+b;
    }
    __declspec(dllexport) int sub(int a, int b)
    {
    return a-b;
    }
    

    可以使用工具查看dll文件内封装起来的函数,查看结果如下:
    在这里插入图片描述
    上图中ordinal为函数的序号,hint表示提示码,rva是表示函数在dll中的地址,name表示函数名。
    我们声明的导出函数为add和sub,但发现name中的函数名并非是add和sub
    原因:
    这是因为在C++中为了支持函数重载,在编译器进行编译链接时,会将函数名和形参一起进行考虑,往往会去篡改函数的名字,按照自己定义的法则去改变函数的名字。这也导致了一个问题:不同的C++的编译器定义的改名的法则并不相同,函数名各不相同。从而使得在调用dll内函数时,会有找不到函数入口的问题

    https://blog.csdn.net/ljianhui/article/details/9005935
    https://www.cnblogs.com/Dageking/p/4054863.html