從extern說開去(一)


extern符號的主要目的是爲了實現C++對C程序的正確調用,在C++中完美兼容C。

包含的含義主要有兩個方面:

(1)extern關鍵字表明函數和全局變量的作用範圍。從鏈接的角度看,意味着在編譯期間會以約定的方式表示引用的在其他模塊中聲明的函數或變量,等到鏈接時再重定位,進行地址修正(絕對地址修正和相對地址修正)。與之相對應的是static,用static聲明後的函數和變量無法被其他模塊引用。

(2)遇到由extern聲明的部分,C++編譯器會以C的方式進行編譯。

逐條來看具體含義。

首先要搞清楚,我們通常所說的編譯並不準確。從源代碼到可執行文件,要經歷4個主要步驟預編譯 -> 編譯 -> 彙編 -> 鏈接。

與extern相關的主要在鏈接和編譯的過程,所以主要講解這兩個過程。

首先看看鏈接(因爲相對簡單)。

鏈接的本質是把多個不同的目標文件互相粘合在一起。編譯器編譯源代碼後生成的文件叫做目標文件,從廣義上看目標文件與可執行文件的結構是一致的,區別在於由於沒有經過鏈接的過程,引用的不是在本模塊內定義的函數和全局變量只能以約定的方式表示,並不能獲得實際的內容。以hello world程序舉例

#include<stdio.h>

int main()
{
    printf("hello world!\n");
    return 0;
}
上述代碼中,調用了printf函數。函數名就是一個指針,指向代表函數代碼片段的入口地址。而函數的代碼片段在哪呢?或者說函數名這個指針指向哪裏呢?答案就是函數定義的模塊。也就是說,對於一個完整的可執行文件,printf指向這個函數代碼片段的位置,也就是指向定義這個函數的模塊的某一個位置。而在鏈接之前,編譯的過程中這個值會以約定的方式代替,鏈接的作用就是將具體的地址填入。

搞清了鏈接的作用,我們就可以知道,對於一個目標文件,它所用的符號(函數和變量統稱爲符號),如果是在它內部定義的(也就是在源代碼中定義),它可以直接獲取到這個符號的地址,即時不鏈接也可以直接用。而對於在其他文件內定義的符號(它所引用的,比如printf),只有在鏈接之後才能獲得具體地址。

既然有可以被其他模塊引用的符號(鏈接之後獲得地址的符號),那麼自然也就有不可以被其他模塊所引用的符號(static聲明)。

這就是extern的第一個含義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章