一個STL物件的DLL邊界傳遞問題

zealotds發表於2011-09-01
c++, DLL, std::string, STL, crt

這裡有非常詳細的一篇[url=http://www.gamedev.net/topic/337108-passing-stdstring-over-dll-boundaries/]討論[/url]僅供參考
也有可能是一個[url=http://support.microsoft.com/kb/172396/en-us/]已知的微軟實現問題[/url]

最近在重構專案時遇到的一個問題:提取了原來專案中的一些公共方法到一個新的DLL,暴露的工具方法中多數以const std::string& 為引數。在除錯時發現當主程式(exe)呼叫DLL中的這些工具方法時傳入的string會發生莫名其妙的變化(不是encoding問題)。比如在主程式中的string的buffer地址為0x0118cd8,可是剛剛進入工具方法(const std::string&)這個string的內容就變了,而且buffer地址也發生了變化,根據觀察只有幾個位元組的偏移。開發環境為VC2008。

[size=large][b]排除過程[/b][/size]
首先檢查了C++的Runtime library,確定都是/MD,另外調整了兩個工程的其它編譯,連線選項到一致,問題依舊。最後在編譯命令列中(Command Line)發現了一個可疑點,_DEBUG預編譯項。可是我明明用的是/MD(Multithreaded DLL),不是/MDd(debug),為什麼會有_DEBUG呢?為了驗證猜測,使用“Undefine Preprocessor Definitions”取消了_DEBUG定義,問題解決!
其實問題的根源在於我這個除錯用的Build Configuration,是基於預設的Debug建立的,這樣,VS或預設為你加上_DEBUG定義,而我們這個專案原來的工程的debug環境都是基於Release配置建立的build configuration。其實不僅是string,STL中的很多型別(不敢說全部)都存在這樣的問題。

[size=large][b]總結[/b][/size]
1. 為了保證程式行為的一致性,DLL與主程式的runtime library最好完全一致,否則便可能引入各種連結和執行時錯誤。
2. DLL的介面方法好暴露C式的方法簽名,這樣一方面可以提高LIB的可用性,還能杜絕STL物件的這種問題。
3. 錯誤的排除可以從編譯器和連結器的的command line引數入手
4. 在為專案新增新的工程時尤其需要注意

相關文章