2014年10月25日

[C++] Name Mangling (名稱修飾)

當初事先 PO 了一篇雜記提醒自己要寫這篇文章果然是明智的決定! 
迷之音:富堅了這麼久還敢說?

這篇要談的主題是 Name Mangling (名稱修飾),這是個 C++ 用來實現 function overloading 的方法,然而這東西卻也可能會導致連結器 (linker) 要把兩個分別用 C 與 C++ 編譯完的 object file 連結起來時出現問題,因此這邊就來淺談這玩意兒。至於與其相關的 Overloading Resolution (重載決議),因為實在有點複雜,需要不少版面來說明,就留到下一篇好了。繼續富堅的意味

修過 / 學過 C++ 的人應該都知道 C++ 支援 overloading,所以你可以把 function 取成相同的名字,然後在 function header 除了回傳值之外的地方有不同之處以供區別即可。
什麼? 你說你不知道? 那你確定你是學 C++? 不過這陣子才聽到一個案例是沒用過 command line 編譯過 C++ 程式,也沒用過 IDE 的超奇怪例子,所以也很難說...但那學生我問了老半天他自己也說得不清不楚,所以我也搞不懂詳細情況到底是怎樣...

C++ 編譯器之所以能做到這件事情,有用到 Name Mangling (名稱修飾)。正如其義,即便你把 function 取成相同名稱,編譯器會自動的幫你把 function name 加一些東西進去,所以原本看似一樣的名稱,實際上編譯器內部在處理時是不同的。所以名稱修飾大致上就是這麼一回事,講完了!

什麼? 覺得我講得太簡略? 阿他概念就這麼簡單阿 (挖鼻) 不然我再多講一些這東西一般人在使用上最常遇到的問題

一般因為名稱修飾引起的問題通常來自要把分別用 C 與 C++ 編譯器編譯完的 object file 連結在一起時,會出現 linked error。通常會看到的錯誤訊息是

undefined reference to XXX

有一定的程式經驗的人,也已經知道這種 linked error 是在告訴你某個 function 你有宣告並使用到他,然而連結器 (linker) 找不到該 function 的定義在哪,所以給你這錯誤訊息。因此當看到這錯誤訊息,我相信大部分的人都會先去找看自己是不是 Makefile 沒寫好? 該一起 link 的 library / object file 有沒有都指定好? 一般來說這種問題這樣應該就都能解掉了。然而,在這過程中,有時後會發現你很確定該指定的、該連結的都有設定好了,但就是噴出這錯誤訊息。這時候可以檢查一下,如果要連結的檔案 / 函式庫有部分是用 C 編譯的,部份卻是用 C++ 編譯的,這時後可能就是名稱修飾在搞鬼。

問題由來大致上是這樣的:
經過名稱修飾後, function name 將不再是原本的名稱,這也意謂著編譯成 object file 後, linker 看到的名稱也不會是原本 function 的名稱,因此當兩個分別用 C 跟 C++ 編譯的 object file 要 link 時,會因為 function name 不一樣,導致 linker 找不到本來應該存在的 function,所以就引發 link error - undefined reference to XXX。

解決方法很簡單,在編譯時把用 C compiler 編譯的那份 object file / library 提供的 header file 用 export "C" { } 包起來就可以了。這東西的用意是告訴 C++ compiler 那裡面的東西是用 C compiler 編譯的,所以不要在呼叫端用名稱修飾過的 function name 來找。於是問題就解決啦!

詳細上 C++ compiler 處理 overloading 的機制不會只有名稱修飾,因為要通盤考慮所有狀況的話,其實會有很多很微妙的問題。再加上 C++ 的 OOP, Generic programming 等等因素考慮進來的話,問題其實十足複雜,不過就談到這裡就好,太深入的東西目前我也還沒搞懂。

沒有留言:

張貼留言