Skip to main content

"Shared library" + "C++" + "static" is evil

Shared library 在 Microsoft windows 上通常是以 .dll 作為檔名結尾,而在 UNIX like 系統上則是以 .so 作為結束。為什麼會有這麼大的差異呢?這是因為 shared library 並沒有一個跨 OS 的 standard 可以遵循,所以在撰寫 C/C++ 程式時就會碰到很多麻煩。

基本上,只要使用到 shared library,這個程式就不 portable 了。所有用來處理 shared library 的機制都不 portable。 Windows 有他自己的一套,UNIX 有它自己的另一套。當 C++ 程式裡面使用到 static 時更是嚴重,如果再加上 template 的話,那基本上就很難去切割的很模組化了。

舉例來說,下面是 dll 的 .h 檔:



再來看 exe 的 .c 檔:



為求完整,附上 dll 的 .c 檔:



這樣子經過 Visual C++ 2008 express edition 編譯後,執行時會發現在 .exe 跟 .dll 內部都會存在一份 static member 的 memory space。所以執行後的結果會得到 .exe 跟 .dll 看到的是不一樣的值:



這是因為在 Visual C++ 中的 default 設定是 .exe 或 .dll 內的 symbol 都不會被 export 出去,如果沒有特別設定的話,都預設是專屬於該 .exe 或 .dll 內部的,也就是說外面是看不到的。所以如果外面也要能夠存取到的話,那麼 Visual C++ 提供一個 keyword,也就是 __declspec(dllimport) 跟 __declspec(dllexport),可以做到這件事情。透過這兩個 keyword 的使用,就可以讓 .exe 檔也能存取 .dll 內的 static member,而不會產生不一致的現象了。所以新的 .dll 的 .h 檔會像是如下所示:





我在 mingw gcc 4.2.3 上做試驗,也得到一樣的結果,一定要加上 __declspec(dllimport) 以及 __declspec(dllexport) 這樣的關鍵字才有用。

<不負責猜想> 我沒有在 linux 版上的 gcc 做試驗,不過我記得 gcc 的 default 行為是 export module 內所有的 symbol,所以我想 linux 版的 gcc 應該是不用加任何 keyword 就應該是 .exe 跟 .so 都只會看到同一份 static member data 才對。

Comments