溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么理解C++內(nèi)鏈接與外鏈接

發(fā)布時(shí)間:2021-11-17 11:07:27 來(lái)源:億速云 閱讀:182 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容主要講解“怎么理解C++內(nèi)鏈接與外鏈接”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“怎么理解C++內(nèi)鏈接與外鏈接”吧!

首先理解什么是編譯單元?

我們知道,其實(shí)編譯器在編譯代碼時(shí),只會(huì)去編譯.cpp格式的源文件,并且預(yù)編譯器會(huì)遞歸的把.cpp所有#include的頭文件都“拷貝”到.cpp文件中去,之后對(duì)這個(gè)文件再進(jìn)行編譯,生成二進(jìn)制的.obj文件。那么其實(shí)每一個(gè).cpp文件都是一個(gè)編譯單元。

聲明與定義

一個(gè)聲明將一個(gè)名稱引入一個(gè)作用域,C++中在同一個(gè)作用域中可以重復(fù)聲明,除了類中的成員函數(shù)與成員變量的聲明。以下都是聲明:

Extern int number; //外部引用聲明

Typedef int  int32; // typedef聲明

Class A;          //類的前置聲明

Using std::cin;   //名字空間引用聲明

Friend f;         //友元聲明

Int testFun();    //函數(shù)前置聲明

定義決定了一個(gè)實(shí)體在一個(gè)作用域的唯一描述,同一作用域不可以重復(fù)定義一個(gè)實(shí)體。以下都是定義:

Int a;

Class Myclass{…};

Myclass ma;

Static int b;

Enum{first, second,third};

Const int m = 2;

Void hello(){…}

什么是內(nèi)部鏈接?

如果一個(gè)名稱對(duì)于他的編譯單元是局部的,并且在鏈接時(shí)不會(huì)與其他的編譯單元中同樣的名字沖突,那么這個(gè)名稱就擁有內(nèi)部鏈接。這個(gè)實(shí)體有內(nèi)部鏈接,他就不會(huì)與其他.cpp文件同名的實(shí)體沖突。換個(gè)說(shuō)法,那些編譯單元(.cpp)中不能向其他編譯單元(.cpp)展示提供其定義的函數(shù)、變量就擁有內(nèi)部鏈接

那么哪些實(shí)體擁有內(nèi)部鏈接?

1.      靜態(tài)(static)全局變量,自由函數(shù),友元函數(shù)定義

2.      類的定義

3.      內(nèi)聯(lián)函數(shù)定義

4.      Union共用體定義

5.      名字空間的const常量定義

6.      枚舉類型定義

7.      所有的聲明(有人將聲明歸結(jié)為無(wú)鏈接)

什么是外部鏈接?

一個(gè)多文件的程序中,一個(gè)實(shí)體可以在鏈接時(shí)與其他編譯單元交互,那么這個(gè)實(shí)體就擁有外部鏈接。

換個(gè)說(shuō)法,那些編譯單元(.cpp)中能想其他編譯單元(.cpp)提供其定義,讓其他編譯單元(.cpp)使用的函數(shù)、變量就擁有外部鏈接

那么哪些實(shí)體擁有外部鏈接?

1.      類的非內(nèi)聯(lián)函數(shù)(包括成員函數(shù)和靜態(tài)類成員函數(shù))的定義

2.      類的靜態(tài)成員變量的定義

3.      名字空間或全局的非靜態(tài)的自由函數(shù),非靜態(tài)變量,非友元函數(shù)的定義

那么這里總結(jié)一下,定義這樣的內(nèi)鏈接與外鏈接有什么意義?

所謂鏈接,就是因?yàn)轫?xiàng)目工程的不斷擴(kuò)大,寫在一個(gè).cpp文件即難以維護(hù),又不好去合作開(kāi)發(fā)。所以去將代碼按照比較有條理的,分成多個(gè)文件,讓其可以獨(dú)立編譯,在最后運(yùn)行在整合到一起,也就是通過(guò)鏈接再去找到需要的代碼。這時(shí)候就需要外鏈接定位到合適的代碼。

比如我們定義的全局函數(shù)和變量,可以跨模塊的鏈接使用。

有一些名字定義所表示的實(shí)體擁有外部鏈接,這樣就意味著他可以跨越編譯單元去進(jìn)行代碼的鏈接。所以,擁有外部鏈接的實(shí)體如果被聲明在頭文件并且被多個(gè).cpp文件包含,可能就會(huì)出現(xiàn)鏈接沖突錯(cuò)誤,因?yàn)槊總€(gè)包含這個(gè)擁有外部鏈接實(shí)體的.cpp都會(huì)分配空間,當(dāng)多個(gè)編譯單元鏈接的時(shí)候,連接器就會(huì)面對(duì)多個(gè)相同的名字,無(wú)法正常鏈接到正確的對(duì)象。

下面舉個(gè)例子:(VS2012環(huán)境下)

//lesson.h

namespace lesson

{
         int  test;

}

//lesson.cpp

#include "stdafx.h"

#include "lesson.h"

int _tmain(intargc,_TCHAR*argv[])

{
         system("pause");

         return0;

}

//test.cpp

#include "lesson.h"

我們就會(huì)看到

error LNK2005: "intlesson::test" (?test@lesson@@3HA) 已經(jīng)在 lesson.obj 中定義C:\Users\user\Documents\Visual Studio 2012\Projects\lesson\lesson\stdafx.obj

這樣的錯(cuò)誤提示。

而對(duì)于擁有內(nèi)部鏈接的實(shí)體則不會(huì)出現(xiàn)這樣的情況,因?yàn)樗粫?huì)與其他.cpp的同名實(shí)體產(chǎn)生沖突。比如我們將上面的lesson.h改為

//lesson.h

class lesson

{
         int  test;

}

這樣就不會(huì)有任何錯(cuò)誤,因?yàn)轭惖亩x是有內(nèi)部鏈接的。

如果在lesson.h里面再定義靜態(tài)變量,枚舉類,進(jìn)行各種聲明等,這些實(shí)體由于有內(nèi)部鏈接所以仍然是合法的,編譯器會(huì)認(rèn)為你想在各個(gè)編譯單元中都有一個(gè)私有的副本。

那么進(jìn)一步的概括這些內(nèi)容就是一句話  

相同作用域內(nèi)的聲明可以有多個(gè),但是只能定義一次。

先不考慮內(nèi)鏈接還是外鏈接,我們都知道一個(gè){}里面不可能定義兩個(gè)一模一樣的名字。對(duì)于一個(gè)單獨(dú)的.cpp文件,我們是知道的,但是對(duì)于多個(gè)文件,好像就稍微有點(diǎn)暈。其實(shí),這是一個(gè)道理,我們的外部鏈接就是讓各個(gè).cpp文件能鏈接到一起,這樣在.cpp文件遇到第一個(gè){}之前,他們的作用域就可以理解為相同的,所以擁有外部鏈接的實(shí)體(全局函數(shù),變量等)出現(xiàn)在第一個(gè){}之前,而且名字相同,那就是出現(xiàn)了定義重復(fù)的錯(cuò)誤。

我們?cè)倏?,所有的聲明都是有?nèi)部鏈接的,然而他其實(shí)可以鏈接到其他文件,因?yàn)樗亩x是在其他的編譯單元的,所以多個(gè)編譯單元擁有相同的聲明也是合理的。但是,我們知道,這個(gè)聲明對(duì)應(yīng)的定義肯定只有一個(gè)。

最后再給出一個(gè)C++編程建議,慎重考慮在頭文件中定義有鏈接的實(shí)體

一,如果頭文件是像int a=1;這樣的定義,被包含在多個(gè).cpp文件后肯定會(huì)報(bào)出鏈接錯(cuò)誤。

二,如果是想static int a = 2;這樣的定義就會(huì)在所有包含他的.cpp文件中生成一個(gè)副本,如果被大量源文件include的話,就會(huì)占據(jù)大量的空間,造成內(nèi)存浪費(fèi)。

到此,相信大家對(duì)“怎么理解C++內(nèi)鏈接與外鏈接”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI