用vs編譯動態庫需要注意的問題,全局變量初始化

用vs編譯動態庫如果配置錯誤會導致全局變量不能初始化。

例子:

string a="hello";
char b="hello";
int main(int arg,char* argv[])
{
printf("string a=%s",a.c_str());
printf("char* b=%s",b);
}

編譯成exe後,你可能會認爲都是輸出“hello”,但實際結果不盡如此。這取決於你的工程設置。

如果工程屬性裏,鏈接器,入口函數設置爲main,那麼結果只有b被打印了,a爲空:即:string a=char* b=hello;

這是爲什麼呢?

Window和wince的動態庫存在一個入口函數,是_DllMainCRTStartup ,這裏面會調用_CRT_INIT,這裏面會初始化運行時庫的全局變量和靜態全局變量。

其實這一點對於exe應用也是一樣的,但邏輯不同,exe的入口默認是mainCRTStartup,裏面同樣會初始化全局變量和靜態非全局變量。

也就是說如果你設置了入口函數,系統不會調用_CRT_INIT 來執行調用構造函數,但是char* 是c語言

下面是MSDN的解釋:

C/C++ 運行時庫代碼執行 DLL 啓動序列,從而不必像 Windows 3.x 中那樣必須鏈接到單獨的模塊。C/C++ 運行時庫代碼中包含的是名爲 _DllMainCRTStartup 的 DLL 入口點函數。_DllMainCRTStartup 函數執行若干操作,其中包括調用 _CRT_INIT,此操作初始化 C/C++ 運行時庫並在靜態非局部變量上調用 C++ 構造函數。如果沒有此函數,運行時庫將保持未初始化狀態。_CRT_INIT 既可以用於靜態鏈接的 CRT,也可以從用戶 DLL 鏈接到 CRT DLL Msvcrt.dll。

雖然可以使用 /ENTRY: 鏈接器選項指定其他入口點函數,但不建議這樣做,因爲新的入口點函數將不得不重複_DllMainCRTStartup 執行的所有操作。用 Visual C++ 生成 DLL 時,系統自動鏈接 _DllMainCRTStartup,您無需使用 /ENTRY: 鏈接器選項指定入口點函數。

除了初始化 C 運行時庫外,_DllMainCRTStartup 還調用名爲 DllMain 的函數。根據生成的 DLL 類型的不同,Visual C++ 爲您提供 DllMain 並使它被鏈接,以便 _DllMainCRTStartup 始終有東西可以調用。這樣,如果不需要初始化 DLL,則在生成 DLL 時沒有什麼特別的事情要做。如果需要初始化 DLL,添加代碼的位置取決於編寫的 DLL 類型。有關更多信息,請參見初始化 DLL

C/C++ 運行時庫代碼在靜態非局部變量上調用構造函數和析構函數。例如,在以下 DLL 源代碼中,Equus 和 Sugar 是 CHorse 類的兩個靜態非本地對象,它們都是在 Horses.h 中定義的。由於這些對象是在所有函數的外部定義的,源代碼中沒有任何函數包含對CHorse 的構造函數或對析構函數的調用。因此,必須由運行時代碼執行對這些構造函數和析構函數的調用。應用程序的運行時庫代碼也執行此函數。

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