在編譯鏈接的時候鏈接器需要將符號解析爲相應的對象。
首先有這樣幾個原則:在同一個命名空間內的符號,是相互可見的。
這裏的命名空間是一個很抽象的概念,例如一個function本身可以看作一個命名空間,它所有的局部變量,只在內部可見;函數執行完畢後由於棧平衡的作用使得這些局部變量全部銷燬。顯然可以推測,對於局部符號以及被static修飾的符號,不會存在什麼符號可見性的問題。
但是對於全局符號就完全不一樣了。一個全局符號(例如全局變量)可能會在多處定義或者引用,編譯器爲了正確的處理這些關係,便定義了強弱符號和強弱引用的概念。
強符號:一個定義並且初始化過的全局符號。例如下面:
int strong = 0;
void iamstrong() {}
弱符號:一個定義但是未初始化過的全局符號。例如:
int week;
強引用:對某個符號的顯式引用。鏈接期間若該引用的定義不存在則會出錯。
弱引用:基本上同強引用,但是鏈接期間若找不到該引用定義也不會報錯。
下面這個程序:
void bar();
int main(void) {
bar();
return 0;
}
一般來說,如果直接編譯鏈接,則會報bar符號找不到的鏈接錯誤。顯然,這裏的bar就是一個強引用。
利用GCC內置一個聲明,將bar聲明爲弱引用,則編譯鏈接會成功。如下所示:
__attribute__ ((weekref)) void bar();
但是這個程序運行的時候會報錯,因爲bar此時實際上是NULL(0)。