這是Windows和Unix類系統之間一個非常著名的差異。
不管是什麼:
- 每個過程有它自己的地址空間,這意味着永遠不會在進程間共享的任何內存(除非你使用一些進程間通信庫或擴展)。
- 的一個定義規則(ODR)仍然適用,這意味着你只能有全局變量可見在鏈接時(靜態或動態鏈接)的一個定義。
所以,問題的關鍵是在這裏真的知名度。
在所有情況下,static
全局變量(或函數)在模塊外部(dll/so或者可執行文件)永遠不可見。 C++標準要求它們具有內部鏈接,這意味着它們在定義它們的翻譯單元(它成爲目標文件)之外是不可見的。所以,這解決了這個問題。
它變得複雜的是當你有全局變量extern
。在這裏,Windows和類Unix系統完全不同。
對於Windows(.exe和.dll),extern
全局變量不是導出符號的一部分。換句話說,不同的模塊根本不知道其他模塊中定義的全局變量。這意味着如果您嘗試創建一個應該使用DLL中定義的變量的可執行文件(因爲這是不允許的),您將會收到鏈接程序錯誤。您需要提供一個帶有該extern變量定義的目標文件(或靜態庫),並將其與靜態鏈接,這兩個文件均爲可執行文件和DLL,從而生成兩個不同的全局變量(一個屬於可執行文件,一個屬於DLL)。
要實際輸出一個全局變量在Windows中,你必須使用類似功能導出/導入語法中的語法,即:
#ifdef COMPILING_THE_DLL
#define MY_DLL_EXPORT extern "C" __declspec(dllexport)
#else
#define MY_DLL_EXPORT extern "C" __declspec(dllimport)
#endif
MY_DLL_EXPORT int my_global;
當你這樣做,全局變量被添加到列表可以像所有其他功能一樣鏈接導出的符號。
對於類Unix環境(如Linux),動態庫(稱爲「共享對象」,擴展名爲.so
)導出所有extern
全局變量(或函數)。在這種情況下,如果你從任何地方連接到共享目標文件,那麼全局變量是共享的,即作爲一個鏈接在一起。基本上,類Unix系統的設計使其與靜態或動態庫鏈接幾乎沒有區別。同樣,ODR全面應用:全局變量將在模塊之間共享,這意味着它應該只在加載的所有模塊中具有一個定義。
最後,在兩種情況下,Windows或Unix類系統中,你可以做運行時聯的動態庫的,即無論是使用LoadLibrary()
/GetProcAddress()
/FreeLibrary()
或dlopen()
/dlsym()
/dlclose()
。在這種情況下,您必須手動獲取您希望使用的每個符號的指針,其中包含您希望使用的全局變量。對於全局變量,只要全局變量是導出符號列表的一部分(按照前面段落的規則),就可以使用GetProcAddress()
或dlsym()
,就像您對函數做的一樣。
當然,作爲必要的最後說明:應該避免全局變量。我相信你所引用的文本(關於事物「不清楚」)完全是指我剛剛解釋的特定於平臺的差異(動態庫並非真正由C++標準定義,這是特定於平臺的領域,意味着它更不可靠/便攜)。
*模塊*你可能是指* libs *。有一個建議,在C++標準中增加* modules *,並且對於模塊的定義和截至目前的常規庫有着更爲精確的定義。 –
啊,應該澄清一點。我將解決方案中的不同項目(我在Visual Studio中工作很多)視爲模塊。這些模塊內置到* .lib或* .dll中。 – Raja
@DavidRodríguez-dribeas術語「模塊」是獨立(完全鏈接的)可執行文件的正確術語,包括:可執行程序,動態鏈接庫(.dll)或共享對象(.so)。這裏非常合適,意思是正確的,並且很好理解。正如我所解釋的,在有一個名爲「模塊」的標準功能之前,其定義仍然是傳統的功能。 –