(后兩個(gè)聲明是等同的)
char const *pc1; //到const char的指針
const char *pc2; //到const char的指針
從右向左讀的記憶方式:
cp is a const pointer to char.
pc2 is a pointer to const char.
用法3:const修飾函數(shù)傳入?yún)?shù)
將函數(shù)傳入?yún)?shù)聲明為const,以指明使用這種參數(shù)僅僅是為了效率的原因,而不是想讓調(diào)用函數(shù)能夠修改對(duì)象的值。同理,將指針參數(shù)聲明為const,函數(shù)將不修改由這個(gè)參數(shù)所指的對(duì)象。
通常修飾指針參數(shù)和引用參數(shù):
void Fun(const A *in); //修飾指針型傳入?yún)?shù)
void Fun(const A &in); //修飾引用型傳入?yún)?shù)
//注意引用的概念,我得C學(xué)得不夠好!
用法4:修飾函數(shù)返回值
可以阻止用戶修改返回值。返回值也要相應(yīng)的付給一個(gè)常量或常指針。
用法5:const修飾成員函數(shù)
//這個(gè)地方也理解不好啊!
const對(duì)象只能訪問(wèn)const成員函數(shù),而非const對(duì)象可以訪問(wèn)任意的成員函數(shù),包括const成員函數(shù);
const對(duì)象的成員是不能修改的,而通過(guò)指針維護(hù)的對(duì)象確實(shí)可以修改的;
const成員函數(shù)不可以修改對(duì)象的數(shù)據(jù),不管對(duì)象是否具有const性質(zhì)。編譯時(shí)以是否修改成員數(shù)據(jù)為依據(jù)進(jìn)行檢查。
2.static的用法:
全局靜態(tài)變量怎么用??
所謂的全局靜態(tài)變量只在當(dāng)前程序中有效。比如在a.c中定義了
static int i;
則只有a.c中的函數(shù)可以訪問(wèn)i,其它程序模塊的無(wú)法直接訪問(wèn)這個(gè)變量,但可以通過(guò)a.c中所定義的函數(shù)間接訪問(wèn)。比如在a.c中定義兩個(gè)函數(shù):
int get_i()
{
return i;
};
int set_i( int n )
{
i=n;
}
以此獲得及重新設(shè)置i的值。這在c環(huán)境下是一種較好的模擬C++風(fēng)格的實(shí)現(xiàn)方法。因?yàn)槟憧梢詫.c看作一個(gè)類,i看作a的成員,而get_i()和set_i()則看作這個(gè)類的成員函數(shù)。
靜態(tài)變量作用范圍在一個(gè)文件內(nèi),程序開(kāi)始時(shí)分配空間,結(jié)束時(shí)釋放空間,默認(rèn)初始化為0,使用時(shí)可以改變其值。
靜態(tài)變量或靜態(tài)函數(shù)只有本文件內(nèi)的代碼才能訪問(wèn)它,它的名字在其它文件中不可見(jiàn)。
用法1:函數(shù)內(nèi)部聲明的static變量,可作為對(duì)象間的一種通信機(jī)制
如果一局部變量被聲明為static,那么將只有唯一的一個(gè)靜態(tài)分配的對(duì)象,它被用于在該函數(shù)的所有調(diào)用中表示這個(gè)變量。這個(gè)對(duì)象將只在執(zhí)行線程第一次到達(dá)它的定義使初始化。
用法2:局部靜態(tài)對(duì)象
對(duì)于局部靜態(tài)對(duì)象,構(gòu)造函數(shù)是在控制線程第一次通過(guò)該對(duì)象的定義時(shí)調(diào)用。在程序結(jié)束時(shí),局部靜態(tài)對(duì)象的析構(gòu)函數(shù)將按照他們被構(gòu)造的相反順序逐一調(diào)用,沒(méi)有規(guī)定確切時(shí)間。
用法3:靜態(tài)成員和靜態(tài)成員函數(shù)
如果一個(gè)變量是類的一部分,但卻不是該類的各個(gè)對(duì)象的一部分,它就被成為是一個(gè)static靜態(tài)成員。一個(gè)static成員只有唯一的一份副本,而不像常規(guī)的非static成員那樣在每個(gè)對(duì)象里各有一份副本。同理,一個(gè)需要訪問(wèn)類成員,而不需要針對(duì)特定對(duì)象去調(diào)用的函數(shù),也被稱為一個(gè)static成員函數(shù)。
類的靜態(tài)成員函數(shù)只能訪問(wèn)類的靜態(tài)成員(變量或函數(shù))。
3.extern的用法:
extern可以聲明其他文件內(nèi)定義的變量。在一個(gè)程序里,一個(gè)對(duì)象只能定義一次,它可以有多個(gè)聲明,但類型必須完全一樣。如果定義在全局作用域或者名字空間作用域里某一個(gè)變量沒(méi)有初始化,它會(huì)被按照默認(rèn)方式初始化。
將變量或函數(shù)聲明成外部鏈接,即該變量或函數(shù)名在其它函數(shù)中可見(jiàn)。被其修飾的變量(外部變量)是靜態(tài)分配空間的,即程序開(kāi)始時(shí)分配,結(jié)束時(shí)釋放。
在C++中,還可以指定使用另一語(yǔ)言鏈接,需要與特定的轉(zhuǎn)換符一起使用。
extern “C” 聲明語(yǔ)句
extern “C” { 聲明語(yǔ)句塊 }
4.volatile的用法:
類型修正符(type-modifier),限定一個(gè)對(duì)象可被外部進(jìn)程(操作系統(tǒng)、硬件或并發(fā)進(jìn)程等)改變。volatile與變量連用,可以讓變量被不同的線程訪問(wèn)和修改。聲明時(shí)語(yǔ)法:int volatile vInt;
除了基本類型外,對(duì)用戶定義類型也可以用volatile類型進(jìn)行修飾。
注意:可以把一個(gè)非volatile int賦給volatile int,但是不能把非volatile對(duì)象賦給一個(gè)volatile對(duì)象。
一個(gè)有volatile標(biāo)識(shí)符的類只能訪問(wèn)它接口的子集,一個(gè)由類的實(shí)現(xiàn)者控制的子集。用戶只能用const_cast來(lái)獲得對(duì)類型接口的完全訪問(wèn)。此外,volatile向const一樣會(huì)從類傳遞到它的成員。
volatile的本意是“易變的”
由于訪問(wèn)寄存器的速度要快過(guò)RAM,所以編譯器一般都會(huì)作減少存取外部RAM的優(yōu)化。比如:
bit bFlag="0";
int main(void)
{
...
while (1)
{
if (bFlag) dosomething();
}
}
/* 中斷程序*/
void ISR(void)
{
bFlag=1;
}
程序的本意是希望ISR中斷產(chǎn)生時(shí),在main當(dāng)中調(diào)用dosomething函數(shù),但是,由于編譯器判
斷在main函數(shù)里面沒(méi)有修改過(guò)bFlag,因此
可能只執(zhí)行一次對(duì)從bFlag到某寄存器的讀操作,然后每次if判斷都只使用這個(gè)寄存器里面
的“bFlag副本”,導(dǎo)致dosomething永遠(yuǎn)也不會(huì)被調(diào)用。如果將將變量加上volatile修飾,
則編譯器保證對(duì)此變量的讀寫(xiě)操作都不會(huì)被優(yōu)化(肯定執(zhí)行)。此例中bFlag也應(yīng)該如此說(shuō)
明。
volatile是一個(gè)限定符,也稱為keyword或描述符,"volatile 關(guān)鍵字指示字段可由操作系統(tǒng)、硬件或并發(fā)執(zhí)行的線程在程序中進(jìn)行修改。"
當(dāng)要求使用volatile 聲明的變量的值的時(shí)候,系統(tǒng)總是重新從它所在的內(nèi)存讀取數(shù)據(jù),即使它前面的指令剛剛從該處讀取過(guò)數(shù)據(jù)。而且讀取的數(shù)據(jù)立刻被保存。
一般說(shuō)來(lái),volatile用在如下的幾個(gè)地方:
1、中斷服務(wù)程序中修改的供其它程序檢測(cè)的變量需要加volatile;
2、多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile;
3、存儲(chǔ)器映射的硬件寄存器通常也要加volatile說(shuō)明,因?yàn)槊看螌?duì)它的讀寫(xiě)都可能由不同意義;
聲明方式為 volatile declaration
備注
系統(tǒng)總是在 volatile 對(duì)象被請(qǐng)求的那一刻讀取其當(dāng)前值,即使上一條指令從同一對(duì)象請(qǐng)求值。而且,該對(duì)象的值在賦值時(shí)立即寫(xiě)入。
volatile 修飾符通常用于由多個(gè)線程訪問(wèn)而不使用 lock 語(yǔ)句來(lái)序列化訪問(wèn)的字段。使用 volatile 修飾符能夠確保一個(gè)線程檢索由另一線程寫(xiě)入的最新值。
另外,以上這幾種情況經(jīng)常還要同時(shí)考慮數(shù)據(jù)的完整性(相互關(guān)聯(lián)的幾個(gè)標(biāo)志讀了一半被打斷了重寫(xiě)),在1中可以通過(guò)關(guān)中斷來(lái)實(shí)現(xiàn),2中可以禁止任務(wù)調(diào)度,3中則只能依靠硬件的良好設(shè)計(jì)了。
volatile 的含義
volatile總是與優(yōu)化有關(guān),編譯器有一種技術(shù)叫做數(shù)據(jù)流分析,分析程序中的變量在哪里賦值、在哪里使用、在哪里失效,分析結(jié)果可以用于常量合并,常量傳播等優(yōu)化,進(jìn)一步可以死代碼消除。但有時(shí)這些優(yōu)化不是程序所需要的,這時(shí)可以用volatile關(guān)鍵字禁止做這些優(yōu)化,volatile的字面含義是易變的,它有下面的作用:
1 不會(huì)在兩個(gè)***作之間把volatile變量緩存在寄存器中。在多任務(wù)、中斷、甚至setjmp環(huán)境下,變量可能被其他的程序改變,編譯器 自己無(wú)法知道,volatile就是告訴編譯器這種情況。
2 不做常量合并、常量傳播等優(yōu)化,所以像下面的代碼:
volatile int i = 1;
if (i > 0) ...
if的條件不會(huì)當(dāng)作無(wú)條件真。
3 對(duì)volatile變量的讀寫(xiě)不會(huì)被優(yōu)化掉。如果你對(duì)一個(gè)變量賦值但后面沒(méi)用到,編譯器常??梢允÷阅莻€(gè)賦值***作,然而對(duì)Memory Mapped IO的處理是不能這樣優(yōu)化的。
一個(gè)網(wǎng)友說(shuō):volatile的意思是什么?
很多時(shí)候,全局變量不一定是全局的,在多線程環(huán)境下可能產(chǎn)生微妙的錯(cuò)誤,很有可能編譯器為了優(yōu)化,而把一個(gè)全局變量放入寄存器里。volatile修飾符就是明確告訴編譯器,你他媽不準(zhǔn)把這個(gè)變量?jī)?yōu)化到寄存器上,只能放內(nèi)存里。
-----------------------------------------------------------------------------------------------------------------------------
const應(yīng)用:
一、對(duì)于基本聲明
const int r=100;//標(biāo)準(zhǔn)const變量聲明加初始化,編譯器經(jīng)過(guò)類型檢查后直接用100在編譯時(shí)替換。
二、對(duì)于指針
1. int x=10; const int *r=&x; //指針指向的內(nèi)容是常量,r指向的內(nèi)容不能夠通過(guò)r改變,但如果是非const,內(nèi)容可以通過(guò)自己改變,而且r指針可以改變,可以指向其它的整形.
//*r=*r+1;NO //x++;YES //r=&y;YES
2. int const *r=&x; 與1完全相同
3. int * const r=&x; //指針指向是常量,不能修改去指向其它內(nèi)容,但指向的內(nèi)容可以修改
//r=&y;NO //*r=*r+1;YES //x++;YES
4.const int * const r=&x; //綜合1、3用法,r是一個(gè)指向常量的常量型指針,指針指向不能改變,指針內(nèi)容不能改變,內(nèi)容可以自身改變
//r=&y;NO //*r=*r+1;NO //x++;YES
三、對(duì)于類型檢查
可以把非const對(duì)象賦予const指針,這樣就不能改變.但是不能把const賦給非const,除非先強(qiáng)制轉(zhuǎn)換
const int x=100; int *p=(int*)&x; *p++;
四、對(duì)于函數(shù)
1.void Fuction1(const int r); //此處為參數(shù)傳遞const值,意義是變量初值不能被函數(shù)改變
2.const int Fuction1 (int); //此處返回const值,意思指返回的原函數(shù)里的變量的初值不能被修改,但是函數(shù)按值返回的這個(gè)變量被制成副本,能不能被修改就沒(méi)有了意義,它可以被賦給任何的const或非const類型變量,完全不需要加上這個(gè)const關(guān)鍵字。
3.Class CX; //內(nèi)部有構(gòu)造函數(shù),聲明如CX(int r =0)
CX Fuction1 () { return CX(); }
const CX Fuction2 () { return CX(); }
Fuction1() = CX(1); //沒(méi)有問(wèn)題,可以作為左值調(diào)用
Fuction2() = CX(1); //編譯錯(cuò)誤,const返回值禁止作為左值調(diào)用。
4.函數(shù)中指針的const傳遞和返回:
int F1 (const char *pstr); //作為傳遞的時(shí)候使用const修飾可以保證不會(huì)通過(guò)這個(gè)指針來(lái)修改傳遞參數(shù)的初值
const char *F2();//意義是函數(shù)返回的指針指向的對(duì)象是一個(gè)const對(duì)象,它必須賦給一個(gè)同樣是指向const對(duì)象的指針
const char * const F3(); //比上面多了一個(gè)const,這個(gè)const的意義只是在他被用作左值時(shí)有效,它表明了這個(gè)指針除了指向const對(duì)象外,它本身也不能被修改,所以就不能當(dāng)作左值來(lái)處理。
五、對(duì)于類
1.首先,對(duì)于const的成員變量,只能在構(gòu)造函數(shù)里使用初始化成員列表來(lái)初始化,試圖在構(gòu)造函數(shù)體內(nèi)進(jìn)行初始化const成員變量會(huì)引起編譯錯(cuò)誤。初始化成員列表形如:
X:: X ( int ir ): r(ir) {} //假設(shè)r是類X的const成員變量
注意:類的構(gòu)造和析構(gòu)函數(shù)都不能是const函數(shù)。
2.建立了一個(gè)const成員函數(shù),但仍然想用這個(gè)函數(shù)改變對(duì)象內(nèi)部的數(shù)據(jù)。(函數(shù)不能修改類的數(shù)據(jù)成員)
//假如有一個(gè)叫做X的類,它有一個(gè)int成員變量r,我們需要通過(guò)一個(gè)const成員函數(shù)f( )來(lái)對(duì)這個(gè)r進(jìn)行++r操作,代碼如下
void X::f( ) const
{ (const_cast(this)) -> ++r; } //通過(guò)this指針進(jìn)行類型強(qiáng)制轉(zhuǎn)換實(shí)現(xiàn)
--------------------------------STATIC--------------------------------
對(duì)于一個(gè)完整的程序,內(nèi)存中的分布情況:
==========
| 代碼區(qū) |
------------------
| 全局?jǐn)?shù)據(jù)區(qū) |
------------------
| 堆區(qū) |
-----------------
| 棧區(qū) |
==========
一般程序的由new產(chǎn)生的動(dòng)態(tài)數(shù)據(jù)存放在堆區(qū),函數(shù)內(nèi)部的自動(dòng)變量存放在棧區(qū),全局變量和static變量放在全局?jǐn)?shù)據(jù)區(qū)
static的作用主要有以下3個(gè):
1、擴(kuò)展生存期;
2、限制作用域;
3、唯一性
STATIC:
一、面向過(guò)程設(shè)計(jì)中的static
1、[靜態(tài)全局變量] //在全局變量前,加上關(guān)鍵字static,該變量就被定義成為一個(gè)靜態(tài)全局變量。
靜態(tài)全局變量有以下特點(diǎn):
1)該變量在全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存;
2)未經(jīng)初始化的靜態(tài)全局變量會(huì)被程序自動(dòng)初始化為0(自動(dòng)變量的值是隨機(jī)的,除非它被顯式初始化);
3)靜態(tài)全局變量在聲明它的整個(gè)文件都是可見(jiàn)的,而在文件之外(extern)是不可見(jiàn)的;
定義全局變量就可以實(shí)現(xiàn)變量在文件中的共享,但定義靜態(tài)全局變量還有以下好處:
1)靜態(tài)全局變量不能被其它文件所用;
2)其它文件中可以定義相同名字的變量,不會(huì)發(fā)生沖突;
2、[靜態(tài)局部變量] 在局部變量前,加上關(guān)鍵字static,該變量就被定義成為一個(gè)靜態(tài)局部變量。
通常,在函數(shù)體內(nèi)定義了一個(gè)變量,每當(dāng)程序運(yùn)行到該語(yǔ)句時(shí)都會(huì)給該局部變量分配棧內(nèi)存。但隨著程序退出函數(shù)體,系統(tǒng)就會(huì)收回棧內(nèi)存,局部變量也相應(yīng)失效。但有時(shí)候我們需要在兩次調(diào)用之間對(duì)變量的值進(jìn)行保存。通常的想法是定義一個(gè)全局變量來(lái)實(shí)現(xiàn)。但這樣一來(lái),變量已經(jīng)不再屬于函數(shù)本身了,不再僅受函數(shù)的控制,給程序的維護(hù)帶來(lái)不便。
靜態(tài)局部變量正好可以解決這個(gè)問(wèn)題。靜態(tài)局部變量保存在全局?jǐn)?shù)據(jù)區(qū),而不是保存在棧中,每次的值保持到下一次調(diào)用,直到下次賦新值。
靜態(tài)局部變量有以下特點(diǎn):
1)該變量在全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存;
2)靜態(tài)局部變量在程序執(zhí)行到該對(duì)象的聲明處時(shí)被首次初始化,即以后的函數(shù)調(diào)用不再進(jìn)行初始化;
3)靜態(tài)局部變量一般在聲明處初始化,如果沒(méi)有顯式初始化,會(huì)被程序自動(dòng)初始化為0;
4)它始終駐留在全局?jǐn)?shù)據(jù)區(qū),直到程序運(yùn)行結(jié)束。但其作用域?yàn)榫植孔饔糜?,?dāng)定義它的函數(shù)或語(yǔ)句塊結(jié)束時(shí),其作 用域隨之結(jié)束;
3、靜態(tài)函數(shù)
在函數(shù)的返回類型前加上static關(guān)鍵字,函數(shù)即被定義為靜態(tài)函數(shù)。靜態(tài)函數(shù)與普通函數(shù)不同,它只能在聲明它的文件當(dāng)中可見(jiàn),不能被其它文件使用。
定義靜態(tài)函數(shù)的好處:
1)靜態(tài)函數(shù)不能被其它文件所用;
2)其它文件中可以定義相同名字的函數(shù),不會(huì)發(fā)生沖突;
二、面向?qū)ο蟮膕tatic關(guān)鍵字(類中的static關(guān)鍵字)
1、靜態(tài)數(shù)據(jù)成員
在類內(nèi)數(shù)據(jù)成員的聲明前加上關(guān)鍵字static,該數(shù)據(jù)成員就是類內(nèi)的靜態(tài)數(shù)據(jù)成員。
靜態(tài)數(shù)據(jù)成員有以下特點(diǎn):
1)而靜態(tài)數(shù)據(jù)成員被當(dāng)作是類的成員。無(wú)論這個(gè)類的對(duì)象被定義了多少個(gè),靜態(tài)數(shù) 據(jù)成員在程序中也只有一份拷貝,由該類型的所有對(duì)象共享訪問(wèn)。
2)靜態(tài)數(shù)據(jù)成員存儲(chǔ)在全局?jǐn)?shù)據(jù)區(qū),屬于本類的所有對(duì)象共享,所以,它不屬于特定的類對(duì)象,在沒(méi)有產(chǎn)生類對(duì)象時(shí)其作用域就可見(jiàn),即在沒(méi)有產(chǎn)生類的實(shí)例時(shí),我們就可以操作它;
同全局變量相比,使用靜態(tài)數(shù)據(jù)成員有兩個(gè)優(yōu)勢(shì):
1)靜態(tài)數(shù)據(jù)成員沒(méi)有進(jìn)入程序的全局名字空間,因此不存在與程序中其它全局名字沖突的可能性;
2)可以實(shí)現(xiàn)[信息隱藏]。靜態(tài)數(shù)據(jù)成員可以是private成員,而全局變量不能;
2、靜態(tài)成員函數(shù)
它為類的全部服務(wù)而不是為某一個(gè)類的具體對(duì)象服務(wù)。與普通函數(shù)相比,靜態(tài)成員函數(shù)由于不是與任何的 對(duì)象相聯(lián)系,因此它不具有this指針。從這個(gè)意義上講,它無(wú)法訪問(wèn)屬于類對(duì)象的非靜態(tài)數(shù)據(jù)成員,也無(wú)法訪問(wèn)非靜態(tài)成員函數(shù),它只能調(diào)用其余的靜態(tài)成員函數(shù)。
關(guān)于靜態(tài)成員函數(shù),可以總結(jié)為以下幾點(diǎn):
1)出現(xiàn)在類體外的函數(shù)定義不能指定關(guān)鍵字static;
2)靜態(tài)成員之間可以相互訪問(wèn),包括靜態(tài)成員函數(shù)訪問(wèn)靜態(tài)數(shù)據(jù)成員和訪問(wèn)靜態(tài)成員函數(shù);
3)非靜態(tài)成員函數(shù)可以任意地訪問(wèn)靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員;
4)靜態(tài)成員函數(shù)不能訪問(wèn)非靜態(tài)成員函數(shù)和非靜態(tài)數(shù)據(jù)成員
-----------------------------------EXTERN----------------------------
EXTERN
1 基本解釋
extern可以置于變量或者函數(shù)前,以標(biāo)示變量或者函數(shù)的定義在別的文件中,提示編譯器遇到此變量和函數(shù)時(shí)在其他模塊中尋找其定義。通過(guò)這種行為它告訴編譯器:該變量/函數(shù)的定義已經(jīng)存在在某個(gè)地方了,讓編譯器到其他的模塊去尋找它的定義。
另外,extern也可用來(lái)進(jìn)行鏈接指定。
聯(lián)系客服