c 內部鏈結 外部鏈結

2021-05-28 15:30:52 字數 4068 閱讀 7338

c++ 內部鏈結與外部鏈結

2023年03月12日 星期四 11:07

在說內部連線與外部連線前,先說明一些概念。

1.宣告

乙個宣告將乙個名稱引入乙個作用域;

在c++中,在乙個作用域中重複乙個宣告是合法的

以下都是宣告:

int foo(int,int);           //函式前置宣告

typedef int int;             //typedef 宣告

class bar;                   //類前置宣告

extern int g_var;           //外部引用宣告

class bar;                   //類前置宣告

typedef int int;             //typedef 宣告

extern int g_var;           //外部引用宣告

friend test;                 //友員宣告

using std::cout;            //命名空間引用宣告

friend test;                 //友員宣告

using std::cout;             //命名空間引用宣告

int foo(int,int);           //函式前置宣告

在同乙個作用域中你可以多次重複這些宣告。

有兩種宣告不能重複,那就是類成員函式及靜態資料成員的宣告

class foo

;2.定義

乙個定義提供乙個實體(型別、例項、函式)在乙個作用域的唯一描述。

在同一作用域中不可重複定義乙個實體。

以下都是定義:

int y;

class foo ;

struct bar ;

foo* p;

static int i;

enum color;

const double pi = 3.1415;

union rep;

void test(int p) {};

foo a;

bar b;

3.編譯單元

當乙個c或cpp檔案在編譯時,預處理器首先遞迴包含標頭檔案,形成乙個含有所有必要資訊的單個原始檔,這個原始檔就是乙個編譯單元。這個編譯單元會被編譯成為乙個與cpp檔名同名的目標檔案(.o或是.obj)。連線程式把不同編譯單元中產生的符號聯絡起來,構成乙個可執行程式。

4.自由函式

如果乙個函式是自由函式,那麼這個函式不是類的成員函式,也不是友元函式。

下面來看內部連線和外部連線

內部連線:如果乙個名稱對於它的編譯單元來說是區域性的,並且在連線時不會與其它編譯單元中的同樣的名稱相衝突,那麼這個名稱有內部連線(注:有時也將宣告看作是無連線的,這裡我們統一看成是內部連線的)。

以下情況有內部連線:

a)所有的宣告

b)命名空間(包括全域性命名空間)中的靜態自由函式、靜態友元函式、靜態變數的定義

c)enum定義

d)inline函式定義(包括自由函式和非自由函式)

e)類的定義

f)命名空間中const常量定義

g)union的定義

外部連線:在乙個多檔案程式中,如果乙個名稱在連線時可以和其它編譯單元互動,那麼這個名稱就有外部連線。

以下情況有外部連線:

a)類非inline函式總有外部連線。包括類成員函式和類靜態成員函式

b)類靜態成員變數總有外部連線。

c)命名空間(包括全域性命名空間)中非靜態自由函式、非靜態友元函式及非靜態變數

下面舉例說明:

a)宣告、enum定義、union定義有內部連線

所有的宣告、enum定義及union定義在編譯後不會產生連線符號,也就是在不同編譯單元中有相同名稱的宣告及enum、union定義並不會在連線時發生發現多個符號的錯誤。

// main.cpp

typedef int int; //typedef 宣告,內部連線

enum color; //enum定義,內部連線

union x          //union定義,內部連線

;int main(void)

// a.cpp

typedef int int; //在a.cpp中重宣告乙個int型別別名,在連線時不會發生錯誤

enum color; //在a.cpp中重定義了乙個enum color,在連線時不會發生錯誤

const int i =blue; //const常量定義,內部連線

union x            //union定義,內部連線

;b)命名空間中靜態自由函式、靜態友元函式、靜態變數、const常量定義有內部連線

// main.cpp

namespace test

//命名空間靜態函式定義,內部連線

}static int i = 0; //全域性靜態變數定義,內部連線

static int foo() //全域性靜態函式定義,內部連線

const int k = 0; //全域性const常量定義,內部連線

int main(void)

namespace test

//命名空間函式定義,外部連線

}int i = 0; //全域性變數定義,外部連線

int k = 0; //全域性變數定義,外部連線

int foo()

//全域性函式定義,外部連線

在全域性命名空間中,main.cpp中定義了靜態變數i,常量k,及靜態自由函式foo等,這些都有內部連線。如果你將這些變數或函式的static或是const修飾符去掉,在連線時就會出現multiply defined symbols錯誤,它們與a.cpp中的全域性變數、全域性函式發生衝突。

c)類定義總有內部連線,而非inline類成員函式定義總有外部連線,不論這個成員函式是靜態、虛擬還是一般成員函式,類靜態資料成員定義總有外部連線。

1.類的定義有內部連線。如果不是,想象一下你在4個cpp檔案中include定義了類base的標頭檔案,在4個編譯單元中的類base都有外部連線,在連線的時候就會出錯。

看下面的例子:

class b //類定義,內部連線

//類inline函式,內部連線

};struct d

;int b::s_i = 0; //類靜態資料成員定義,外部連線

void d::foo() //類成員函式定義,外部連線

;void d::foo()                 //類成員函式定義,外部連線

這時main.cpp與a.cpp中的d::foo都有外部連線,在連線就會出現multiply defined symbols錯。

3.類的靜態資料成員有外部連線,如上例的b::s_i,這樣當你在main.cpp中定義了類靜態資料成員,其它編譯單元若使用了b::s_i,就會連線到main.cpp對應編譯單元的s_i。

d)inline函式總有內部連線,不論這個函式是什麼函式

// main.cpp

inline int foo()

//inline全域性函式,內部連線

class bar //類定義,內部連線

//inline 類靜態函式,內部連線

int g(int i) //inline 類成員函式,內部連線

};class base

;inline int base::k()

//inline 類成員函式,內部連線

int main(void)

如果你的base類是定義在base.h中,而base的inline 函式是在base.cpp中定義的,那麼在main.cpp中include "base.h"編譯不會出現問題,但在連線時會找不到函式k,所以類的inline函式最好放到標頭檔案中,讓每乙個包含標頭檔案的cpp都能找到inline函式。

現在對c++中的連線有了乙個認識,能清楚的知道是什麼原因產生連線時錯誤。當你在連線時產生連線不到的錯誤,這說明所有的編譯單元都沒有這個實體的外部連線;當你在連線時發現有多個連線實體,這說明有多個編譯單元提供了同名的有外部連線的實體。同時,在進行程式設計時,也要注意不要使只有本編譯單元用到的函式、類、變數等有外部連線,減少與其它編譯單元的連線衝突。

C 的內部鏈結與外部鏈結問題

在說內部連線與外部連線前,先說明一些概念。1.宣告 乙個宣告將乙個名稱引入乙個作用域 在c 中,在乙個作用域中重複乙個宣告是合法的,以下都是宣告 class bar 類前置宣告 typedef int int typedef 宣告 extern int g var 外部引用宣告 friend tes...

C 中的內部鏈結和外部鏈結

c 中的內部連線與外部連線 apr 22nd,2007 by king 一.在學習內部連線與外部連線之前,必須先弄清楚幾個概念 1.宣告 乙個宣告將乙個名稱引入乙個作用域。在c 中,在乙個作用域中重複乙個宣告是合法的。以下都是宣告 int foo int,int 函式前置宣告 typedef int...

外部鏈結建設方案

1.鏈結 2 2 1的比例覆蓋到首頁,站內重要頁面以及其它頁面 15000條外鏈 一月內完成 相關工具 domain analyzer.jsp 2.站內鏈結 收錄頁面1000 三月內完成 3.交叉鏈結和購買鏈結 交易時保證鏈結的穩定和永續性 4.書籤 無所謂nofollow 保留每個社會書籤 的賬號...