包不包含__declspec(dllimport)的判定

按照MSDN說明,當鏈接dll的導出函數時,只需要包含頭文件和lib,__declspec(dllimport)修飾符不是必須的,但加上該修飾能使導出函數的調用效率更高。那麼,究竟原因是什麼?

不使用 __declspec(dllimport) 也能正確編譯代碼,但使用 __declspec(dllimport) 使編譯器可以生成更好的代碼。編譯器之所以能夠生成更好的代碼,是因爲它可以確定函數是否存在於 DLL 中,這使得編譯器可以生成跳過間接尋址級別的代碼,而這些代碼通常會出現在跨 DLL 邊界的函數調用中。但是,必須使用 __declspec(dllimport) 才能導入 DLL 中使用的變量。  

假設dll導出了一個函數:
  extern "C" __declspec(dllexport) void fun();


一、如果程序中聲明不加__declspec(dllimport),查看調用fun()函數的彙編代碼:
     004010AD    call         fun (004010d8)

  其中fun被定義爲一個標號(label),如下:
fun:
     004010D8    jmp          dword ptr [__imp__fun (0040e0e8)]

    上面的符號__imp__fun指向的地址爲fun()函數在exe中的導入節。

二、當聲明加上__declspec(dllimport)後,查看調用fun()函數的彙編代碼:

     004010AB    call         dword ptr [__imp__fun (0040e0e8)]

    從上面可以看出,加上__declspec(dllimport),編譯器鏈接dll將省略一條jmp語句。

這是因爲:

1。如果導出函數的聲明沒有用__declspec(dllimport) 修飾的話,編譯器並不知道這個函數是由DLL導出的,所以編譯器就把這個函數當作普通的外部引用來對待,產生一個外部引用的符號等着鏈接器解析。當鏈接器工作的時候,它是不能修改編譯器生成的結果,所以會將該符號解析爲對相應函數調入節的間接調用。

2。如果導出函數的聲明用__declspec(dllimport) 修飾的話,編譯器一開始就知道這個函數是DLL導出函數,直接編譯成對調入節的調用。

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