2011-04-29 120 views
0

大多數在UNIX上工作的人經常會面臨這種令人煩惱的錯誤。 有時需要更少的時間來解決,有時會花費很多時間。未找到符號AKA未定義的符號

即使我經常遇到這樣和我需要一些好的文件或關於c中的特定錯誤的文章/ C++

哪些地方有可能是找不到符號/未定義的符號錯誤的所有情況。

有人能幫我知道那些情況是什麼嗎?

+0

在什麼情況下? – 2011-04-29 07:19:40

+0

編譯時出現鏈接器錯誤 – Vijay 2011-04-29 09:11:17

回答

1

對於大多數情況下,當您找到符號未找到/未定義符號或有時甚至是「重複符號」錯誤時,它們通常源自鏈接程序無法在您嘗試的項目中找到該符號的事實建立。

最好的方法是查看生成的映射文件或作爲編譯器輸出的符號表。它可能是這個樣子:

Symbols

這將讓你看到如果符號存在或不存在。此外,還可能存在其他深奧的問題,例如編譯器優化,可能會導致符號重複,特別是內聯彙編。這些是最難以發現的。

至於良好的資源和材料,我沒有很多很好的參考。當我問到那時,大多數高級工程師實際上已經從他們自己的經驗中學到了東西。

但是我相信這樣的論壇可以幫助我們加快獲取知識。

希望它幫助:)

乾杯!

+0

我很抱歉,但我一直在試圖上傳圖片,以便獲得示例視圖,但無濟於事。我確實選擇了要上傳的小jpg文件,但它一直被拒絕。我在某個地方出了問題嗎? – Vern 2011-04-29 07:36:19

3

該錯誤與UNIX/Windows /任何其他操作系統無關,而與語言本身無關。使用編譯器提供的信息進行診斷實際上很簡單。通常他們會告訴你什麼符號丟失了,有時候會在哪裏使用。對於失蹤的象徵,主要理由是:

  • 您已經聲明,但從未將它定義
  • 您已經定義它,但沒有編譯符號(目標文件/庫)添加到鏈接
  • 它是外部的,您忘記鏈接庫,或者您鏈接的是無效版本,或者順序錯誤。

第一個是,如果你打算定義符號,但不匹配的聲明(聲​​明void foo(int, double);,但定義void foo(double, int)有點棘手。與所有其他情況下,編譯器會告訴你確切的簽名確保你已經定義了這個符號,而不是某個特定的或者類似的東西,如果你在聲明和定義中使用了不同的調用約定,那麼特定的角落案例可能會是,因爲它們看起來非常相似在代碼中。

在庫外部代碼的情況下,複雜性在於確定哪些庫需要鏈接以便添加該符號,並且來自lib的文檔。請注意,使用靜態庫時,鏈接器命令行中的庫的順序會影響結果。

爲了幫助您找到實際定義的符號,您可以使用nm(gcc,這在UNIX系統中很常見)。所以基本上你可以運行nm針對你正在鏈接的目標文件/庫,並搜索鏈接器正在抱怨的符號。這將有助於在順序是造成差異的情況下(即符號在那裏,但鏈接器跳過它)。在運行時(感謝Matthieu M.指出),如果在LD_LIBRARY_PATH中找到錯誤版本的庫,那麼您可能會遇到與動態庫類似的問題,您最終可能會得到一個沒有所需的符號。

+1

當然,微妙的問題是,你在鏈接時聲明瞭一個依賴關係,但不幸的是'LD_LIBRARY_PATH'不像你所期望的那樣,並且最終(在加載時)與不同版本的庫鏈接,未定義您所期望的符號(例如,二進制兼容性問題)。 – 2011-04-29 08:48:48

+0

@Matthieu M.很好,我只是在編譯時考慮。 – 2011-04-29 09:09:25

+0

我只使用DLLs,所以對我來說這是一個經常性問題:) – 2011-04-29 09:12:40

1

我假設你指的是鏈接器錯誤。以下列出了我認爲最常見到最不常見的一個列表:

  • 您忘了告訴鏈接器有關依賴關係(例如LIB文件)的信息。
  • 你有一個靜態數據成員的類,忘記初始化它(只有C++)。
  • 您聲明的函數不是純粹虛擬的,並且忘記實現它。
  • 你忘了實現一個你從另一個函數中調用的函數(只有C,C++會給出一個更容易找到的編譯器錯誤)。
  • 您聲明瞭一個外部變量並忘記初始化它。
  • 該函數的聲明與實現不匹配(只有C++,C會接受它並可能死亡)。
  • 您忘記了實現您從另一個函數聲明和調用的函數。
+0

如果你忘記實現一個函數,C++編譯器就不會告訴你這個問題。它將滿足函數聲明。 – 2011-04-29 08:46:12

+0

@MatthieuM:嗯,有兩個子彈處理這個(第四和最後)。兩者之間的差異很小但很重要。在C中,你可以調用一個函數而不必先聲明它。如果您未能定義(實現)它,鏈接器將會投訴。在C++中,如果沒有編譯器的抱怨,你不能使用未聲明的函數。這是第4號子彈的意思。現在,如果你確實聲明瞭它,但沒有定義它,鏈接器會抱怨C和C++。這是最後一顆子彈的意思。 – 2011-12-10 22:05:27

2

雖然他們可以依賴於平臺,我有一些來自安德烈亞斯和大衛點的一些「更加複雜」實例:

  • 當共享庫(.so or.dll)和處理鏈接到未導出的符號(Windows上的dllimport/dllexport以及* nix上的GCC的可見性(「默認」))
  • 或類似:鏈接靜態庫,期望共享庫,反之亦然。這與Mathieu關於鏈接另一個意外版本庫的評論有些相似。
  • 創建一個純虛擬類,並且不爲至少一個方法提供實現(不會導致vtable可用)。
  • 實際上是一個更復雜的聲明但未定義的情況:處理大型嵌套模板時可能會遇到鏈接錯誤。查找大量錯誤消息可能很難找出未定義的內容。