__declspec(dllimport)有什麼用?

摘抄自: http://blog.csdn.net/mniwc/article/details/7993361

    我們通常在編寫DLL時會用到這兩個宏。比如現在我新建一個DLL工程:DllDlg。然後我新建兩個文件:DllApi.h和DllApi.cpp。DllApi.h作爲接口文 件,DllApi.cpp作爲實現文件。

    接着在DllApi.h聲明一個函數:

__declspec(dllexport) void HelloWorld(); </span>

    在DllApi.cpp寫這個函數的實現:

    void HelloWorld()  
    {  
        AfxMessageBox(_T("HelloWorld"));  
    }  

    這樣外部的應用程序或dll就能調用HelloWorld函數。這裏要特別提醒的是:有些網友說要把DllApi.h中的__declspec(dllexport) void HelloWorld();改爲__declspec(dllimport) void HelloWorld();才能提供給外部調用,實際上這並不需要,這個我已經測試過


    而我們經常的用法是這樣的

    #ifdef _EXPORTING  
    #define API_DECLSPEC    __declspec(dllexport)  
    #else  
    #define API_DECLSPEC    __declspec(dllimport)  
    #endif  </span>

    是不是就只剩下一種作用:讓外部調用者看得更自然些,知道哪些接口是自己工程需要導入的?__declspec(dllimport)是不是一點實際作用都沒有呢?看到mniwc的文章,才明白其實不然,結論如下:

1. 在導入動態鏈接庫中的全局變量方面起作用

    使用

   #ifdef _EXPORTING  
   #define API_DECLSPEC    __declspec(dllexport)  
   #else  
   #define API_DECLSPEC    __declspec(dllimport)  
   #endif 
    可以更好地導出dll中的全局變量,比如按照的宏,可以在dll中這樣導出全局變量:

   API_DECLSPEC CBtt g_Btt;  
    然後在調用程序這樣導入:

   API_DECLSPEC CBtt g_Btt;  
  

    當然也可以使用extern關鍵字,比如在dll中這樣導出全局變量:


   CBtt g_Btt;  
    然後在調用程序這樣導入:
   extern CBtt g_Btt;  
    但據說使用__declspec(dllimport)更有效。


2. __declspec(dllimport)的作用主要體現在導出類的靜態成員方面
    比如在動態鏈接庫中定義這樣一個導出類:

    class __declspec(dllexport) CBtt  
    {  
    public:  
        CBtt(void);  
        ~CBtt(void);  
    public:  
        CString m_str;  
        static int GetValue()  
        {  
            return m_nValue;  
        }  
    private:  
        static int m_nValue;  
    };  
    照上面這樣聲明,外部雖然可以使用CBtt類,但不能使用CBtt類的GetValue函數,一使用就會出現無法解析的外部符號  

        "public: static int CBtt::m_nValue" (?m_nValue@CBtt@@2HA)。只有如下聲明才能使用CBtt類的GetValue函數:

    #ifdef _EXPORTING  
    #define API_DECLSPEC    __declspec(dllexport)  
    #else  
    #define API_DECLSPEC    __declspec(dllimport)  
    #endif  
    class API_DECLSPEC CBtt  
    {  
    public:  
        CBtt(void);  
        ~CBtt(void);  
    public:  
        CString m_str;  
        static int GetValue()  
        {  
            return m_nValue;  
        }  
    private:  
        static int m_nValue;  
    };  


3. 使用隱式使用dll時,不加__declspec(dllimport)完全可以,使用上沒什麼區別,只是在生成的二進制代碼上稍微有點效率損失

    a、不加__declspec(dllimport)時,在使用dll中的函數時,編譯器並不能區別這是個普通函數,還是從其它dll裏導入的函數,

          所以其生成的代碼如下:

          call 地址1

          地址1:
               jmp 實際函數地址


    b、有__declspec(dllimport)時,編譯器知道這是要從外部dll導入的函數,從而在生成的exe的輸入表裏留有該項,以便在

          運行exe,PE載入器加載exe時對輸入地址表IAT進行填寫,這樣生成的代碼如下:

                call dword ptr[輸入表裏哪項對應的內存地址] (注意:現在就不需要jmp stub了)。

          這裏有興趣的朋友可以參看《編譯原理》和 PE文件格式。


4.使用__declspec(dllimport)體現了語言的一種對稱美,比如雖然!true就是表示false,但是我們還是需要false這個關鍵字,這裏體現了一種對稱美。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章