1、什么是指針
(1)在C語(yǔ)言中,訪問(wèn)變量的方式有兩種,通過(guò)變量訪問(wèn),通過(guò)地址訪問(wèn)。指針存放的就是地址。

(2)野指針和懸空指針:野指針,就是沒(méi)有被初始化的指針,懸空指針,最初指向的內(nèi)存已經(jīng)被釋放了的指針。無(wú)論是野指針還是懸空指針,都是指向無(wú)效內(nèi)存區(qū)域(這里的無(wú)效指的是"不安全不可控")的指針。 訪問(wèn)"不安全可控"(invalid)的內(nèi)存區(qū)域?qū)?dǎo)致"Undefined Behavior"。
(3)指針和引用的區(qū)別:指針和引用都是地址的概念,指針指向一塊內(nèi)存,它的內(nèi)容是所指內(nèi)存的地址;引用是某塊內(nèi)存的別名。本質(zhì),引用是別名,指針是地址。使用指針的優(yōu)點(diǎn)和必要性:指針能夠有效的表示數(shù)據(jù)結(jié)構(gòu);能動(dòng)態(tài)分配內(nèi)存,實(shí)現(xiàn)內(nèi)存的自由管理;能較方便的使用字符串;便捷高效地使用數(shù)組指針直接與數(shù)據(jù)的儲(chǔ)存地址有關(guān):
★條款一:指針與引用的區(qū)別
指針與引用看上去完全不同(指針用操作符’*’和’->’,引用使用操作符’.’),但是它們似乎有相同的功能。指針與引用都是讓你間接引用其他對(duì)象。你如何決定在什么時(shí)候使用指針,在什么時(shí)候使用引用呢?
首先,要認(rèn)識(shí)到在任何情況下都不能用指向空值的引用。一個(gè)引用必須總是指向某些對(duì)象。因此如果你使用一個(gè)變量并讓它指向一個(gè)對(duì)象,但是該變量在某些時(shí)候也可能不指向任何對(duì)象,這時(shí)你應(yīng)該把變量聲明為指針,因?yàn)檫@樣你可以賦空值給該變量。相反,如果變量肯定指向一個(gè)對(duì)象,例如你的設(shè)計(jì)不允許變量為空,這時(shí)你就可以把變量聲明為引用。但是,請(qǐng)等一下”,你懷疑地問(wèn),“這樣的代碼會(huì)產(chǎn)生什么樣的后果?
char*pc =0;// 設(shè)置指針為空值
char& rc = *pc;// 讓引用指向空值
這是非常有害的,毫無(wú)疑問(wèn)。結(jié)果將是不確定的(編譯器能產(chǎn)生一些輸出,導(dǎo)致任何事情都有可能發(fā)生),應(yīng)該躲開(kāi)寫出這樣代碼的人除非他們同意改正錯(cuò)誤。如果你擔(dān)心這樣的代碼會(huì)出現(xiàn)在你的軟件里,那么你最好完全避免使用引用,要不然就去讓更優(yōu)秀的程序員去做。我們以后將忽略一個(gè)引用指向空值的可能性。因?yàn)橐每隙〞?huì)指向一個(gè)對(duì)象,在C里,引用應(yīng)被初始化。
不存在指向空值的引用這個(gè)事實(shí)意味著使用引用的代碼效率比使用指針的要高。因?yàn)樵谑褂靡弥安恍枰獪y(cè)試它的合法性。
string& rs;// 錯(cuò)誤,引用必須被初始化
strings("xyzzy");
string&rs = s;// 正確,rs指向s指針沒(méi)有這樣的限制。
string*ps;// 未初始化的指針// 合法但危險(xiǎn)
voidprintDouble(constdouble& rd)
{
cout<< rd;// 不需要測(cè)試rd,它
}// 肯定指向一個(gè)double值
相反,指針則應(yīng)該總是被測(cè)試,防止其為空:
voidprintDouble(constdouble*pd)
{
if(pd)
{// 檢查是否為NULL
cout<< *pd;
}
}
指針與引用的另一個(gè)重要的不同是指針可以被重新賦值以指向另一個(gè)不同的對(duì)象。但是引用則總是指向在初始化時(shí)被指定的對(duì)象,以后不能改變。
strings1("Nancy");
strings2("Clancy");
string& rs = s1;// rs 引用 s1
string*ps= &s1;// ps 指向 s1
rs = s2;// rs 仍舊引用s1
// 但是s1的值現(xiàn)在是"Clancy"
ps = &s2;// ps 現(xiàn)在指向 s2;// s1 沒(méi)有改變
總的來(lái)說(shuō),在以下情況下你應(yīng)該使用指針,一是你考慮到存在不指向任何對(duì)象的可能(在這種情況下,你能夠設(shè)置指針為空),二是你需要能夠在不同的時(shí)刻指向不同的對(duì)象(在這種情況下,你能改變指針的指向)。如果總是指向一個(gè)對(duì)象并且一旦指向一個(gè)對(duì)象后就不會(huì)改變指向,那么你應(yīng)該使用引用。還有一種情況,就是當(dāng)你重載某個(gè)操作符時(shí),你應(yīng)該使用引用。最普通的例子是操作符[]。這個(gè)操作符典型的用法是返回一個(gè)目標(biāo)對(duì)象,其能被賦值。但是這樣會(huì)使得v看上去象是一個(gè)向量指針。因此你會(huì)選擇讓操作符返回一個(gè)引用。(這有一個(gè)有趣的例外,參見(jiàn)條款30)當(dāng)你知道你必須指向一個(gè)對(duì)象并且不想改變其指向時(shí),或者在重載操作符并為防止不必要的語(yǔ)義誤解時(shí),你不應(yīng)該使用指針。而在除此之外的其他情況下,則應(yīng)使用指針。
2、strut和union的區(qū)別,什么是內(nèi)存對(duì)齊
共用體和結(jié)構(gòu)體都是由多個(gè)不同的數(shù)據(jù)類型成員組成, 但在任何同一時(shí)刻, 共用體只存放一個(gè)被選中的成員, 而結(jié)構(gòu)體則存放所有的成員變量。對(duì)于共用體的不同成員賦值,將會(huì)對(duì)其他成員重寫, 原來(lái)成員的值就不存在了, 而對(duì)于結(jié)構(gòu)體的不同成員賦值是互不影響的。內(nèi)存分配不同。
為什么要內(nèi)存對(duì)齊:(轉(zhuǎn)) 內(nèi)存對(duì)齊 | Light.Moon,
內(nèi)存讀取粒度:程序員通常認(rèn)為,內(nèi)存就像一個(gè)字節(jié)數(shù)組,然而處理器(CPU)不是按照字節(jié)來(lái)存儲(chǔ)的,一般會(huì)以雙字節(jié),四字節(jié),八字節(jié),16字節(jié),甚至是32字節(jié)為單位來(lái)存取內(nèi)存。所以為了增加速度,就有了內(nèi)存對(duì)齊。
高層(語(yǔ)言)程序員認(rèn)為的內(nèi)存形態(tài)和處理器對(duì)內(nèi)存的實(shí)際處理方式之間的差異產(chǎn)生了許多有趣的問(wèn)題.如果你不理解內(nèi)存對(duì)齊,你編寫的程序?qū)⒂锌赡墚a(chǎn)生下面的問(wèn)題,按嚴(yán)重程度遞增:程序運(yùn)行速度變慢,應(yīng)用程序產(chǎn)生死鎖,操作系統(tǒng)崩潰,你的程序會(huì)毫無(wú)征兆的出錯(cuò),產(chǎn)生錯(cuò)誤的結(jié)果。
內(nèi)存對(duì)齊的例子:在實(shí)際的編程中(以 C++ 語(yǔ)言為例),編譯器都會(huì)為你自動(dòng)對(duì)齊的。在結(jié)構(gòu)中,編譯器為結(jié)構(gòu)的每個(gè)成員按其自身的自然對(duì)界(alignment)條件分配空間。各個(gè)成員按照它們被聲明的順序在內(nèi)存中順序存儲(chǔ),**第一個(gè)成員的地址和整個(gè)結(jié)構(gòu)的地址相同。
規(guī)則:1、第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中,比較小的那個(gè)進(jìn)行。2、在數(shù)據(jù)成員完成各自對(duì)齊之后,類(結(jié)構(gòu)或聯(lián)合)本身也要進(jìn)行對(duì)齊,對(duì)齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長(zhǎng)度中,比較小的那個(gè)進(jìn)行。明顯#pragma pack(n)作為一個(gè)預(yù)編譯指令用來(lái)設(shè)置多少個(gè)字節(jié)對(duì)齊的。值得注意的是,n的缺省數(shù)值是按照編譯器自身設(shè)置,一般為8,合法的數(shù)值分別是1、2、4、8、16。即編譯器只會(huì)按照1、2、4、8、16的方式分割內(nèi)存。若n為其他值,是無(wú)效的。
class test
{
private:
char c = '1';//1byte
int i;//4byte
short s=2;//2byte
};
class test2
{
int i;
char c;
short s;
};
(1)對(duì)于類test的內(nèi)存空間是這樣的:

內(nèi)存分配過(guò)程:
1、char和編譯器默認(rèn)的內(nèi)存缺省分割大小比較,char比較小,分配一個(gè)字節(jié)給它。
2、int和編譯器默認(rèn)的內(nèi)存缺省分割大小比較,int比較小,占4字節(jié)。只能空3個(gè)字節(jié),重新分配4個(gè)字節(jié)。
3、short和編譯器默認(rèn)的內(nèi)存缺省分割大小比較,short比較小,占2個(gè)字節(jié),分配2個(gè)字節(jié)給它。
4、對(duì)齊結(jié)束類本身也要對(duì)齊,所以最后空余的2個(gè)字節(jié)也被test占用。
(2)對(duì)于類test2的內(nèi)存空間是這樣的:

1)、int和編譯器默認(rèn)的內(nèi)存缺省分割大小比較,int比較小,占4字節(jié)。分配4個(gè)字節(jié)給int。
2)、char和編譯器默認(rèn)的內(nèi)存缺省分割大小比較,char比較小,分配一個(gè)字節(jié)給它。
3)、short和編譯器默認(rèn)的內(nèi)存缺省分割大小比較,short比較小,此時(shí)前面的char分配完畢還余下3個(gè)字節(jié),足夠short的2個(gè)字節(jié)存儲(chǔ),所以short緊挨著。分配2個(gè)字節(jié)給short。
4)、對(duì)齊結(jié)束類本身也要對(duì)齊,所以最后空余的1個(gè)字節(jié)也被test占用。
3、什么是多態(tài),單繼承和多繼承的虛函數(shù)表
C++中的虛函數(shù)的作用主要是實(shí)現(xiàn)了多態(tài)的機(jī)制。關(guān)于多態(tài),簡(jiǎn)而言之就是用父類型別的指針指向其子類的實(shí)例,然后通過(guò)父類的指針調(diào)用實(shí)際子類的成員函數(shù)。這種技術(shù)可以讓父類的指針有“多種形態(tài)”,這是一種泛型技術(shù)。所謂泛型技術(shù),說(shuō)白了就是試圖使用不變的代碼來(lái)實(shí)現(xiàn)可變的算法。比如:模板技術(shù),RTTI技術(shù),虛函數(shù)技術(shù),要么是試圖做到在編譯時(shí)決議,要么試圖做到運(yùn)行時(shí)決議。
4、關(guān)鍵字violatile
violatile 的作用,是否具有原子性,對(duì)編譯器有什么影響
volatile 關(guān)鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(tǒng)、硬件或者其它線程等。遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對(duì)訪問(wèn)該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對(duì)特殊地址的穩(wěn)定訪問(wèn)。聲明時(shí)語(yǔ)法:int volatile vInt; 當(dāng)要求使用 volatile 聲明的變量的值的時(shí)候,系統(tǒng)總是重新從它所在的內(nèi)存讀取數(shù)據(jù),即使它前面的指令剛剛從該處讀取過(guò)數(shù)據(jù)。而且讀取的數(shù)據(jù)立刻被保存。
volatile關(guān)鍵字是防止在共享的空間發(fā)生讀取的錯(cuò)誤。只保證其可見(jiàn)性,不保證原子性;使用volatile指每次從內(nèi)存中讀取數(shù)據(jù),而不是從編譯器優(yōu)化后的緩存中讀取數(shù)據(jù),簡(jiǎn)單來(lái)講就是防止編譯器優(yōu)化。
在單任務(wù)環(huán)境中,如果在兩次讀取變量之間不改變變量的值,編譯器就會(huì)發(fā)生優(yōu)化,會(huì)將RAM中的值賦值到寄存器中;由于訪問(wèn)寄存器的效率要高于RAM,所以在需要讀取變量時(shí),直接寄存器中獲取變量的值,而不是從RAM中。
在多任務(wù)環(huán)境中,雖然在兩次讀取變量之間不改變變量的值,在一些情況下變量的值還是會(huì)發(fā)生改變,比如在發(fā)生中斷程序或者有其他的線程。這時(shí)候如果編譯器優(yōu)化,依舊從寄存器中獲取變量的值,修改的值就得不到及時(shí)的響應(yīng)(在RAM還未將新的值賦值給寄存器,就已經(jīng)獲取到寄存器的值)。
要想防止編譯器優(yōu)化,就需要在聲明變量時(shí)加volatile關(guān)鍵字,加關(guān)鍵字后,就在RAM中讀取變量的值,而不是直接在寄存器中取值。
什么場(chǎng)景一定要使用 violatile
一般說(shuō)來(lái),volatile用在如下的幾個(gè)地方:
- 中斷服務(wù)程序中修改的供其它程序檢測(cè)的變量需要加volatile;
- 多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile;
- 存儲(chǔ)器映射的硬件寄存器通常也要加volatile說(shuō)明,因?yàn)槊看螌?duì)它的讀寫都可能由不同意義;
多線程下的volatile
有些變量是用volatile關(guān)鍵字聲明的。當(dāng)兩個(gè)線程都要用到某一個(gè)變量且該變量的值會(huì)被改變時(shí),應(yīng)該用volatile聲明,該關(guān)鍵字的作用是防止優(yōu)化編譯器把變量從內(nèi)存裝入CPU寄存器中。如果變量被裝入寄存器,那么兩個(gè)線程有可能一個(gè)使用內(nèi)存中的變量,一個(gè)使用寄存器中的變量,這會(huì)造成程序的錯(cuò)誤執(zhí)行。volatile的意思是讓編譯器每次操作該變量時(shí)一定要從內(nèi)存中真正取出,而不是使用已經(jīng)存在寄存器中的值,如下:
volatile BOOL bStop = FALSE;
(1) 在一個(gè)線程中:
while( !bStop ) { ... }
bStop = FALSE;
return;
(2) 在另外一個(gè)線程中,要終止上面的線程循環(huán):
bStop = TRUE;
while( bStop );
等待上面的線程終止,如果bStop不使用volatile申明,那么這個(gè)循環(huán)將是一個(gè)死循環(huán),因?yàn)閎Stop已經(jīng)讀取到了寄存器中,寄存器中bStop的值永遠(yuǎn)不會(huì)變成FALSE,加上volatile,程序在執(zhí)行時(shí),每次均從內(nèi)存中讀出bStop的值,就不會(huì)死循環(huán)了。
這個(gè)關(guān)鍵字是用來(lái)設(shè)定某個(gè)對(duì)象的存儲(chǔ)位置在內(nèi)存中,而不是寄存器中。因?yàn)橐话愕膶?duì)象編譯器可能會(huì)將其的拷貝放在寄存器中用以加快指令的執(zhí)行速度,例如下段代碼中:
int nMyCounter = 0;
for(; nMyCounter<100;nMyCounter++)
{
}
在此段代碼中,nMyCounter的拷貝可能存放到某個(gè)寄存器中(循環(huán)中,對(duì)nMyCounter的測(cè)試及操作總是對(duì)此寄存器中的值進(jìn)行),但是另外又有段代碼執(zhí)行了這樣的操作:nMyCounter -= 1;這個(gè)操作中,對(duì)nMyCounter的改變是對(duì)內(nèi)存中的nMyCounter進(jìn)行操作,于是出現(xiàn)了這樣一個(gè)現(xiàn)象:nMyCounter的改變不同步。
violatile 能否和 const 一起用
文章基礎(chǔ):
(1) “編譯器一般不為const變量分配內(nèi)存,而是將它保存在符號(hào)表中,這使得它成為一個(gè)編譯期間的值,沒(méi)有了存儲(chǔ)與讀內(nèi)存的操作。”
(2) volatile的作用是“告訴編譯器,i是隨時(shí)可能發(fā)生變化的,每次使用它的時(shí)候必須從內(nèi)存中取出i的值”。 《c語(yǔ)言深度解剖》
const, volatile含義
(1)const含義是“請(qǐng)做為常量使用”,而并非“放心吧,那肯定是個(gè)常量”。
(2)volatile的含義是“請(qǐng)不要做自以為是的優(yōu)化,這個(gè)值可能變掉的”,而并非“你可以修改這個(gè)值”。
const, volatile的作用以及起作用的階段
(1)const只在編譯期有用,在運(yùn)行期無(wú)用
const在編譯期保證在C的“源代碼”里面,沒(méi)有對(duì)其修飾的變量進(jìn)行修改的地方(如有則報(bào)錯(cuò),編譯不通過(guò)),而運(yùn)行期該變量的值是否被改變則不受const的限制。
(2) volatile在編譯期和運(yùn)行期都有用
在編譯期告訴編譯器:請(qǐng)不要做自以為是的優(yōu)化,這個(gè)變量的值可能會(huì)變掉;在運(yùn)行期:每次用到該變量的值,都從內(nèi)存中取該變量的值。
補(bǔ)充:編譯期 -- C編譯器將源代碼轉(zhuǎn)化為匯編,再轉(zhuǎn)化為機(jī)器碼的過(guò)程;運(yùn)行期 -- 機(jī)器碼在CPU中執(zhí)行的過(guò)程。
const, volatile同時(shí)修飾一個(gè)變量
(1)合法性
“volatile”的含義并非是“non-const”,volatile 和 const 不構(gòu)成反義詞,所以可以放一起修飾一個(gè)變量。
(2)同時(shí)修飾一個(gè)變量的含義
表示一個(gè)變量在程序編譯期不能被修改且不能被優(yōu)化;在程序運(yùn)行期,變量值可修改,但每次用到該變量的值都要從內(nèi)存中讀取,以防止意外錯(cuò)誤。
5、new和malloc
new 和 malloc 的區(qū)別:查看另一篇文章
6、inline 實(shí)現(xiàn)原理
基本定義
inline是C++語(yǔ)言中的一個(gè)關(guān)鍵字,可以用于程序中定義內(nèi)聯(lián)函數(shù),inline的引進(jìn)使內(nèi)聯(lián)函數(shù)的定義更加簡(jiǎn)單。說(shuō)到內(nèi)聯(lián)函數(shù),這里給出比較常見(jiàn)的定義,內(nèi)聯(lián)函數(shù)是C++中的一種特殊函數(shù),它可以像普通函數(shù)一樣被調(diào)用,但是在調(diào)用時(shí)并不通過(guò)函數(shù)調(diào)用的機(jī)制而是通過(guò)將函數(shù)體直接插入調(diào)用處來(lái)實(shí)現(xiàn)的,這樣可以大大減少由函數(shù)調(diào)用帶來(lái)的開(kāi)銷,從而提高程序的運(yùn)行效率。一般來(lái)說(shuō)inline用于定義類的成員函數(shù)。
inline的基本使用
inline 返回值類型 函數(shù)名(函數(shù)參數(shù)){
//此處定義函數(shù)體
}
一般來(lái)說(shuō),inline適用的函數(shù)有兩種,一種是在類內(nèi)定義的成員函數(shù),另一種是在類內(nèi)聲明,類外定義的成員函數(shù),對(duì)于這兩種情況inline的使用有一些不同:
(1)類內(nèi)定義成員函數(shù)
這種情況下,我們可以不用在函數(shù)頭部加inline關(guān)鍵字,因?yàn)榫幾g器會(huì)自動(dòng)將類內(nèi)定義的函數(shù)聲明為內(nèi)聯(lián)函數(shù),代碼如下:
class temp{
public:
int amount;
//構(gòu)造函數(shù)
temp(int amount){
this->amount = amount;
}
//普通成員函數(shù),在類內(nèi)定義時(shí)前面可以不加inline
void print_amount(){
cout << this-> amount;
}
}
從上面的代碼可以看出,在類內(nèi)定義函數(shù)時(shí),可以不加inline關(guān)鍵字,編譯器會(huì)自動(dòng)將類內(nèi)定義的函數(shù)(構(gòu)造函數(shù)、析構(gòu)函數(shù)、普通成員函數(shù)等)設(shè)置為內(nèi)聯(lián),具有內(nèi)聯(lián)函數(shù)調(diào)用的性質(zhì)。
(2) 類內(nèi)聲明函數(shù),在類外定義函數(shù)
根據(jù)C++編譯器的規(guī)則,這種情況下如果想將該函數(shù)設(shè)置為內(nèi)聯(lián)函數(shù),則可以在類內(nèi)聲明時(shí)不加inline關(guān)鍵字,而在類外定義函數(shù)時(shí)加上inline關(guān)鍵字,代碼如下所示:
class temp{
public:
int amount;
//構(gòu)造函數(shù)
temp(int amount){
this->amount = amount;
}
//普通成員函數(shù),在類內(nèi)聲明時(shí)前面可以不加inline
void print_amount()
}
//在類外定義函數(shù)體,必須在前面加上inline關(guān)鍵字
inline void temp:: print_amount(){
cout << amount << endl;
}
從上面代碼我們可以看出,類內(nèi)聲明可以不用加上inline關(guān)鍵字,但是類外定義函數(shù)體時(shí)必須要加上,這樣才能保證編譯器能夠識(shí)別其為內(nèi)聯(lián)函數(shù)。另外,我們可以在聲明函數(shù)和定義函數(shù)的同時(shí)寫inline,也可以只在函數(shù)聲明時(shí)加inline,而定義函數(shù)時(shí)不加inline。只要在調(diào)用該函數(shù)之前把inline的信息告知編譯系統(tǒng),編譯系統(tǒng)就會(huì)在處理函數(shù)調(diào)用時(shí)按內(nèi)聯(lián)函數(shù)處理。也就是說(shuō),上面說(shuō)的幾種方法都可以實(shí)現(xiàn)一個(gè)內(nèi)聯(lián)函數(shù)的定義,根據(jù)自己的需要來(lái)寫即可。
內(nèi)聯(lián)函數(shù)的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1.inline 定義的類的內(nèi)聯(lián)函數(shù),函數(shù)的代碼被放入符號(hào)表中,在使用時(shí)直接進(jìn)行替換,(像宏一樣展開(kāi)),沒(méi)有了調(diào)用的開(kāi)銷,效率也很高。
2.很明顯,類的內(nèi)聯(lián)函數(shù)也是一個(gè)真正的函數(shù),編譯器在調(diào)用一個(gè)內(nèi)聯(lián)函數(shù)時(shí),會(huì)首先檢查它的參數(shù)的類型,保證調(diào)用正確。然后進(jìn)行一系列的相關(guān)檢查,就像對(duì)待任何一個(gè)真正的函數(shù)一樣。這樣就消除了它的隱患和局限性。(宏替換不會(huì)檢查參數(shù)類型,安全隱患較大)
3.inline函數(shù)可以作為一個(gè)類的成員函數(shù),與類的普通成員函數(shù)作用相同,可以訪問(wèn)一個(gè)類的私有成員和保護(hù)成員。內(nèi)聯(lián)函數(shù)可以用于替代一般的宏定義,最重要的應(yīng)用在于類的存取函數(shù)的定義上面。
缺點(diǎn):
1.內(nèi)聯(lián)函數(shù)具有一定的局限性,內(nèi)聯(lián)函數(shù)的函數(shù)體一般來(lái)說(shuō)不能太大,如果內(nèi)聯(lián)函數(shù)的函數(shù)體過(guò)大,一般的編譯器會(huì)放棄內(nèi)聯(lián)方式,而采用普通的方式調(diào)用函數(shù)。(換句話說(shuō)就是,你使用內(nèi)聯(lián)函數(shù),只不過(guò)是向編譯器提出一個(gè)申請(qǐng),編譯器可以拒絕你的申請(qǐng))這樣,內(nèi)聯(lián)函數(shù)就和普通函數(shù)執(zhí)行效率一樣了。
2.nline說(shuō)明對(duì)編譯器來(lái)說(shuō)只是一種建議,編譯器可以選擇忽略這個(gè)建議。比如,你將一個(gè)長(zhǎng)達(dá)1000多行的函數(shù)指定為inline,編譯器就會(huì)忽略這個(gè)inline,將這個(gè)函數(shù)還原成普通函數(shù),因此并不是說(shuō)把一個(gè)函數(shù)定義為inline函數(shù)就一定會(huì)被編譯器識(shí)別為內(nèi)聯(lián)函數(shù),具體取決于編譯器的實(shí)現(xiàn)和函數(shù)體的大小。
內(nèi)聯(lián)函數(shù)和宏定義的區(qū)別
內(nèi)聯(lián)函數(shù)和宏的區(qū)別在于,宏是由預(yù)處理器對(duì)宏進(jìn)行替代,而內(nèi)聯(lián)函數(shù)是通過(guò)編譯器控制來(lái)實(shí)現(xiàn)的。而且內(nèi)聯(lián)函數(shù)是真正的函數(shù),只是在需要用到的時(shí)候,內(nèi)聯(lián)函數(shù)像宏一樣的展開(kāi),所以取消了函數(shù)的參數(shù)壓棧,減少了調(diào)用的開(kāi)銷。你可以象調(diào)用函數(shù)一樣來(lái)調(diào)用內(nèi)聯(lián)函數(shù),而不必?fù)?dān)心會(huì)產(chǎn)生于處理宏的一些問(wèn)題。內(nèi)聯(lián)函數(shù)與帶參數(shù)的宏定義進(jìn)行下比較,它們的代碼效率是一樣,但是內(nèi)聯(lián)歡函數(shù)要優(yōu)于宏定義,因?yàn)閮?nèi)聯(lián)函數(shù)遵循的類型和作用域規(guī)則,它與一般函數(shù)更相近,在一些編譯器中,一旦關(guān)聯(lián)上內(nèi)聯(lián)擴(kuò)展,將與一般函數(shù)一樣進(jìn)行調(diào)用,比較方便。
另外,宏定義在使用時(shí)只是簡(jiǎn)單的文本替換,并沒(méi)有做嚴(yán)格的參數(shù)檢查,也就不能享受C++編譯器嚴(yán)格類型檢查的好處,另外它的返回值也不能被強(qiáng)制轉(zhuǎn)換為可轉(zhuǎn)換的合適的類型,這樣,它的使用就存在著一系列的隱患和局限性。
C++的inline的提出就是為了完全取代宏定義,因?yàn)閕nline函數(shù)取消了宏定義的缺點(diǎn),又很好地繼承了宏定義的優(yōu)點(diǎn),《Effective C++》中就提到了盡量使用Inline替代宏定義的條款,足以說(shuō)明inline的作用之大。
使用注意事項(xiàng)
1.內(nèi)聯(lián)函數(shù)不能包括復(fù)雜的控制語(yǔ)句,如循環(huán)語(yǔ)句和switch語(yǔ)句;
2.內(nèi)聯(lián)函數(shù)不能包括復(fù)雜的控制語(yǔ)句,如循環(huán)語(yǔ)句和switch語(yǔ)句;
3.只將規(guī)模很?。ㄒ话?個(gè)語(yǔ)句一下)而使用頻繁的函數(shù)聲明為內(nèi)聯(lián)函數(shù)。在函數(shù)規(guī)模很小的情況下,函數(shù)調(diào)用的時(shí)間開(kāi)銷可能相當(dāng)于甚至超過(guò)執(zhí)行函數(shù)本身的時(shí)間,把它定義為內(nèi)聯(lián)函數(shù),可大大減少程序運(yùn)行時(shí)間。
C++中不但可以用define定義常量還可以用const定義常量,它們的區(qū)別如下:
用#define MAX 255定義的常量是沒(méi)有類型的,所給出的是一個(gè)立即數(shù),編譯器只是把所定義的常量值與所定義的常量的名字聯(lián)系起來(lái),define所定義的宏變量在預(yù)處理的時(shí)候進(jìn)行替換,在程序中使用到該常量的地方都要進(jìn)行拷貝替換;
用const float MAX = 255; 定義的常量有類型名字,存放在內(nèi)存的靜態(tài)區(qū)域中,在程序運(yùn)行過(guò)程中const變量只有一個(gè)拷貝,而#define 所定義的宏變量卻有多個(gè)拷貝,所以宏定義在程序運(yùn)行過(guò)程中所消耗的內(nèi)存要比const變量的大得多;
用define定義的常量是不可以用指針變量去指向的,用const定義的常量是可以用指針去指向該常量的地址的;
用define可以定義一些簡(jiǎn)單的函數(shù),const是不可以定義函數(shù)的.
具體來(lái)說(shuō),有以下幾方面的區(qū)別:
1).編譯器處理方式
define – 在預(yù)處理階段進(jìn)行替換
const – 在編譯時(shí)確定其值
2).類型檢查
define – 無(wú)類型,不進(jìn)行類型安全檢查,可能會(huì)產(chǎn)生意想不到的錯(cuò)誤
const – 有數(shù)據(jù)類型,編譯時(shí)會(huì)進(jìn)行類型檢查
3).內(nèi)存空間
define – 不分配內(nèi)存,給出的是立即數(shù),有多少次使用就進(jìn)行多少次替換,在內(nèi)存中會(huì)有多個(gè)拷貝,消耗內(nèi)存大
const – 在靜態(tài)存儲(chǔ)區(qū)中分配空間,在程序運(yùn)行過(guò)程中內(nèi)存中只有一個(gè)拷貝
4).其他
在編譯時(shí), 編譯器通常不為const常量分配存儲(chǔ)空間,而是將它們保存在符號(hào)表中,這使得它成為一個(gè)編譯期間的常量,沒(méi)有了存儲(chǔ)與讀內(nèi)存的操作,使得它的效率也很高。
宏替換只作替換,不做計(jì)算,不做表達(dá)式求解。
宏定義的作用范圍僅限于當(dāng)前文件。
默認(rèn)狀態(tài)下,const對(duì)象只在文件內(nèi)有效,當(dāng)多個(gè)文件中出現(xiàn)了同名的const變量時(shí),等同于在不同文件中分別定義了獨(dú)立的變量。
如果想在多個(gè)文件之間共享const對(duì)象,必須在變量定義之前添加extern關(guān)鍵字(在聲明和定義時(shí)都要加)。