2012-01-24 52 views
0

我正在使用遺留代碼,並且遇到一個奇怪的問題。我有可執行文件,它使用名爲dbaccess.so的.so庫。在.so和可執行文件中定義的extern變量做未定義的行爲?

我也有一個名爲「lib_base」的庫,並且這個庫靜態鏈接到兩個項目(dbaccess.so和可執行文件)。

   ________ 
      |lib_base| 
      |________| 
     /   \ 
     /statically \ 
     / linked  \ 
______/    \ _____________ 
|my_app|     | dbaccess.so | 
|______| <---dinamically |_____________| 

的問題是,將 「lib_base」 裏面,我有一個.cpp(misc.cpp)文件定義爲

char apName[_MAX_FNAME]; 

和一個.cpp(clientconn.cpp內的可變)在「dbaccess.so」我有:

extern char apName[_MAX_FNAME]; 

我注意到代碼中的一些奇怪的行爲。看起來像「extern」變量混淆了my_app的lib_base中的「apName」的定義和dbaccess的lib_base中的定義。

調試時使用gdb一個DBACCESS'功能時,會發生以下情況:

strcpy(apName, "test"); 
printf(apName); 
在控制檯

,‘測試’被打印出來,但如果我寫在gdb的控制檯下面一行的strcpy後:

print apName 

它打印「apfile.ini」。

有人知道這個問題是否真的與「lib_base」鏈接到這兩個項目有關?編譯dbaccess.so時是否有任何編譯標誌或某些可以傳遞的內容來避免這種情況?

我使用linux和gcc作爲編譯器。

+2

不應該是相反,頭文件中的'extern ...'_declaration_和源文件中的實際_definition_?否則,變量將在包含標題的所有源文件中定義。 –

+0

對不起,我在編寫問題時犯了一個錯誤。我編輯了問題並修復了它。謝謝! –

+0

您是否需要另一個原因來避免全局變量? –

回答

1

如果您在.cpp文件中定義一個只能在該文件中可見的變量,則應該使用static

如果你想共享兩個lib_base之間的值,那麼你不應該靜態鏈接兩次 - 你得到的代碼和數據都是重複的,這既低效又混亂。

C++有這個東西那叫一個定義規則,說你可以定義同樣的事情很多次,只要你喜歡(這樣你就可以包含多個cpp文件相同的頭文件),而且只要他們都定義同樣的,它會正常工作。基本上這意味着鏈接器可以丟棄重複的對象,並隨意保留一個。如果打破ODR編譯器不會知道,並且鏈接器可能不知道,並且然後您得到未定義的行爲。

在這種情況下,您並未破壞ODR,但您已將同一事物鏈接到兩個不同的對象(您的應用程序和共享庫),這是一個不同的問題。動態鏈接器(在運行時加載共享庫)不擔心任何這些廢話 - 它所做的只是將應用中的未定義符號連接到庫中的定義。你的主應用程序中的apName顯然不是未定義的,所以動態鏈接器在那裏沒有什麼可做的,所以這裏沒有未定義的行爲。

假設您不希望lib_base的兩個實例共享aPname的定義,那麼您的應用程序似乎已經鏈接好了(printf證明了這一點),但是GDB在模糊符號名稱中表現不佳。當GDB查找符號名稱時,它不一定知道首先查找的位置,所以不會得到您所期望的。

有時GDB可以自己排序,如果你第一次做list main(或其他)來設置你想要的上下文。基本上,不要複製代碼 - 調試器不會喜歡它。

如果你必須這樣做,檢查出symbol-tableadd-symbol-table命令 - 你可以選擇只從一個文件或其它負載符號和調試所需的位。

+0

謝謝,非常好的解釋! –

相關問題