一 static用法
1箕戳、限制作用域
這一點(diǎn)相對(duì)于普通全局變量和static全局變量來(lái)說(shuō)的惜互。
對(duì)于全局變量而言,不論是普通全局 變量還是static全局變量,其存儲(chǔ)區(qū)都是靜態(tài)存儲(chǔ)區(qū),因此在內(nèi)存分配上沒(méi)有什么區(qū)別。
區(qū) 別在于:
1) (*extern)普通的全局變量和函數(shù)硫狞,其作用域?yàn)檎麄€(gè)程序或項(xiàng)目,外部文件(其它c(diǎn)pp文件)可以通過(guò)extern關(guān)鍵字訪問(wèn)該變量和函數(shù)晃痴。一般不提倡這種用法残吩,如果要在多個(gè)cpp文件間共享數(shù)據(jù),應(yīng)該將數(shù)據(jù)聲明為extern類型倘核。
在頭文件里聲明為extern:
extern int g_value; // 注意泣侮,不要初始化值
然后在其中任何一個(gè)包含該頭文件的cpp中初始化(一次)就好:
int g_value = 0; // 初始化一樣不要extern修飾,因?yàn)閑xtern也是聲明性關(guān)鍵字紧唱;
然后所有包含該頭文件的cpp文件都可以用g_value這個(gè)名字訪問(wèn)相同的一個(gè)變量活尊;
2)static全局變量和函數(shù),其作用域?yàn)楫?dāng)前cpp文件漏益,其它的cpp文件不能訪問(wèn)該變量和函數(shù)蛹锰。如果有兩個(gè)cpp文件聲明了同名的全局靜態(tài)變量,那么他們實(shí)際上是獨(dú)立的兩個(gè)變量绰疤。
static函數(shù)的好處是不同的人編寫不同的函數(shù)時(shí)铜犬,不用擔(dān)心自己定義的函數(shù),是否會(huì)與其它文件中的函數(shù)同名轻庆。
在頭文件中的static變量
如果在一個(gè)頭文件中聲明:
static int g_vaule = 0;
那么會(huì)為每個(gè)包含該頭文件的cpp都創(chuàng)建一個(gè)全局變量癣猾,但他們都是獨(dú)立的;所以也不建議這樣的寫法榨了,一樣不明確需要怎樣使用這個(gè)變量煎谍,因?yàn)橹皇莿?chuàng)建了一組同名而不同作用域的變量。
2龙屉、數(shù)據(jù)唯一性
這是C++對(duì)static關(guān)鍵字的重用呐粘。主要指靜態(tài)數(shù)據(jù)成員/成員函數(shù)。
表示屬于一個(gè)類而不是屬于此類的任何特定對(duì)象的變量和函數(shù). 這是與普通成員函數(shù)的最大區(qū)別, 也是其應(yīng)用所在, 比如在對(duì)某一個(gè)類的對(duì)象進(jìn)行計(jì)數(shù)時(shí), 計(jì)數(shù)生成多少個(gè)類的實(shí)例, 就可以用到靜態(tài)數(shù)據(jù)成員. 在這里面, static既不是限定作用域的, 也不是擴(kuò)展生存期的作用, 而是指示變量/函數(shù)在此類中的唯一性. 這也是”屬于一個(gè)類而不是屬于此類的任何特定對(duì)象的變量和函數(shù)”的含義. 因?yàn)樗菍?duì)整個(gè)類來(lái)說(shuō)是唯一的, 因此不可能屬于某一個(gè)實(shí)例對(duì)象的. (針對(duì)靜態(tài)數(shù)據(jù)成員而言, 成員函數(shù)不管是否是static, 在內(nèi)存中只有一個(gè)副本, 普通成員函數(shù)調(diào)用時(shí), 需要傳入this指針, static成員函數(shù)調(diào)用時(shí), 沒(méi)有this指針. )
static數(shù)據(jù)成員的初始化:
- (1) 初始化在類體外進(jìn)行转捕,而前面不加static作岖,以免與一般靜態(tài)變量或?qū)ο笙嗷煜?/li>
- (2) 初始化時(shí)不加該成員的訪問(wèn)權(quán)限控制符private,public等五芝。
- (3) 初始化時(shí)使用作用域運(yùn)算符來(lái)標(biāo)明它所屬類痘儡,因此,靜態(tài)數(shù)據(jù)成員是類的成員枢步,而不是對(duì)象的成員沉删。
- (4) 靜態(tài)數(shù)據(jù)成員是靜態(tài)存儲(chǔ)的渐尿,它是靜態(tài)生存期,必須對(duì)它進(jìn)行初始化矾瑰。
Static成員函數(shù)
靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員一樣砖茸,它們都屬于類的靜態(tài)成員,它們都不是對(duì)象成員殴穴。因此凉夯,對(duì)靜態(tài)成員的引用不需要用對(duì)象名。
靜態(tài)成員函數(shù)僅能訪問(wèn)靜態(tài)的數(shù)據(jù)成員采幌,不能訪問(wèn)非靜態(tài)的數(shù)據(jù)成員劲够,也不能訪問(wèn)非靜態(tài)的成員函數(shù),這是由于靜態(tài)的成員函數(shù)沒(méi)有this指針休傍。
3 在C語(yǔ)言中征绎,static的字面意思很容易把我們導(dǎo)入歧途,其實(shí)它的作用有三條磨取。
(1)先來(lái)介紹它的第一條也是最重要的一條:隱藏炒瘸。
當(dāng)我們同時(shí)編譯多個(gè)文件時(shí),所有未加static前綴的全局變量和函數(shù)都具有全局可見(jiàn)性寝衫。為理解這句話,我舉例來(lái)說(shuō)明拐邪。我們要同時(shí)編譯兩個(gè)源文件慰毅,一個(gè)是a.c,另一個(gè)是main.c扎阶。
下面是a.c的內(nèi)容
char a = 'A'; // global variable
void msg()
{
printf("Hello\n");
}
下面是main.c的內(nèi)容
int main(void)
{
extern char a; // extern variable must be declared before use
printf("%c ", a);
(void)msg();
return 0;
}
程序的運(yùn)行結(jié)果是:
A Hello
你可能會(huì)問(wèn):為什么在a.c中定義的全局變量a和函數(shù)msg能在main.c中使用汹胃?前面說(shuō)過(guò),所有未加static前綴的全局變量和函數(shù)都具有全局可見(jiàn)性东臀,其它的源文件也能訪問(wèn)着饥。此例中,a是全局變量惰赋,msg是函數(shù)宰掉,并且都沒(méi)有加static前綴,因此對(duì)于另外的源文件main.c是可見(jiàn)的赁濒。
如果加了static轨奄,就會(huì)對(duì)其它源文件隱藏。例如在a和msg的定義前加上static拒炎,main.c就看不到它們了挪拟。利用這一特性可以在不同的文件中定義同名函數(shù)和同名變量,而不必?fù)?dān)心命名沖突击你。Static可以用作函數(shù)和變量的前綴玉组,對(duì)于函數(shù)來(lái)講谎柄,static的作用僅限于隱藏,而對(duì)于變量惯雳,static還有下面兩個(gè)作用朝巫。(2)static的第二個(gè)作用是保持變量?jī)?nèi)容的持久。存儲(chǔ)在靜態(tài)數(shù)據(jù)區(qū)的變量會(huì)在程序剛開(kāi)始運(yùn)行時(shí)就完成初始化吨凑,也是唯一的一次初始化捍歪。共有兩種變量存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū):全局變量和static變量,只不過(guò)和全局變量比起來(lái)鸵钝,static可以控制變量的可見(jiàn)范圍糙臼,說(shuō)到底static還是用來(lái)隱藏的。雖然這種用法不常見(jiàn)恩商,但我還是舉一個(gè)例子变逃。
#include <stdio.h>
int fun(void){
static int count = 10; // 事實(shí)上此賦值語(yǔ)句從來(lái)沒(méi)有執(zhí)行過(guò)
return count--;
}
int count = 1;
int main(void)
{
printf("global\t\tlocal static\n");
for(; count <= 10; ++count)
printf("%d\t\t%d\n", count, fun());
return 0;
}
程序的運(yùn)行結(jié)果是:
global local static
1 10
2 9
3 8
4 7
5 6
6 5
7 4
8 3
9 2
10 1
(3)static的第三個(gè)作用是默認(rèn)初始化為0。其實(shí)全局變量也具備這一屬性怠堪,因?yàn)槿肿兞恳泊鎯?chǔ)在靜態(tài)數(shù)據(jù)區(qū)揽乱。在靜態(tài)數(shù)據(jù)區(qū),內(nèi)存中所有的字節(jié)默認(rèn)值都是0x00粟矿,某些時(shí)候這一特點(diǎn)可以減少程序員的工作量凰棉。比如初始化一個(gè)稀疏矩陣,我們可以一個(gè)一個(gè)地把所有元素都置0陌粹,然后把不是0的幾個(gè)元素賦值撒犀。如果定義成靜態(tài)的,就省去了一開(kāi)始置0的操作掏秩。再比如要把一個(gè)字符數(shù)組當(dāng)字符串來(lái)用或舞,但又覺(jué)得每次在字符數(shù)組末尾加’\0’太麻煩。如果把字符串定義成靜態(tài)的蒙幻,就省去了這個(gè)麻煩映凳,因?yàn)槟抢锉緛?lái)就是’\0’。不妨做個(gè)小實(shí)驗(yàn)驗(yàn)證一下邮破。
#include <stdio.h>
int a;
int main(void)
{
int i;
static char str[10];
printf("integer: %d; string: (begin)%s(end)", a, str);
return 0;
}
程序的運(yùn)行結(jié)果如下
integer: 0; string: (begin)(end)
最后對(duì)static的三條作用做一句話總結(jié)诈豌。首先static的最主要功能是隱藏,其次因?yàn)閟tatic變量存放在靜態(tài)存儲(chǔ)區(qū)决乎,所以它具備持久性和默認(rèn)值0队询。
二 extern
extern修飾的關(guān)鍵字,具有文件外部鏈接构诚,但是聲明extern變量時(shí)蚌斩,編譯器并不會(huì)給這個(gè)變量分配內(nèi)存,在另外的文件中定義這個(gè)文件時(shí)才會(huì)為其分配內(nèi)存,一旦聲明了extern關(guān)鍵字送膳,對(duì)編譯器來(lái)意味著:
- 這個(gè)變量聲明(即數(shù)據(jù)類型和變量名员魏,但是編譯器并沒(méi)有分配內(nèi)存)
- 這個(gè)變量的定義在其他文件中(在定義變量的文件中編譯器才會(huì)為其分配內(nèi)存)
最好將extern變量的聲明放在頭文件中,將變量的定義放在一個(gè)源文件中叠聋。
1 頭文件 (參考2.1.1)
在頭文件里聲明為extern:
extern int g_value; // 注意撕阎,不要初始化值
然后在其中任何一個(gè)包含該頭文件的cpp中初始化(一次)就好:
int g_value = 0; // 初始化一樣不要extern修飾,因?yàn)閑xtern也是聲明性關(guān)鍵字碌补;
然后所有包含該頭文件的cpp文件都可以用g_value這個(gè)名字訪問(wèn)相同的一個(gè)變量虏束;
2 當(dāng)我們同時(shí)編譯多個(gè)文件時(shí),所有未加static前綴的全局變量和函數(shù)都具有全局可見(jiàn)性厦章。
參考2.3.1 與1相同
三 匿名空間
當(dāng)定義一個(gè)命名空間時(shí)镇匀,可以忽略這個(gè)命名空間的名稱:
namespce {
char c;
int i;
double d;
}
編譯器在內(nèi)部會(huì)為這個(gè)命名空間生成一個(gè)唯一的名字,而且還會(huì)為這個(gè)匿名的命名空間生成一條using指令袜啃。
(編譯器會(huì)為匿名空間在當(dāng)前源文件中生成一個(gè)唯一的名字汗侵,使當(dāng)前的文件對(duì)匿名空間中的變量可見(jiàn))
所以上面的代碼在效果上等同于:
namespace __UNIQUE_NAME_ {
char c;
int i;
double d;
}
using namespace __UNIQUE_NAME_;
在匿名命名空間中聲明的名稱也將被編譯器轉(zhuǎn)換,與編譯器為這個(gè)匿名命名空間生成的唯一內(nèi)部名稱(即這里的_UNIQUE_NAME)綁定在一起群发。還有一點(diǎn)很重要晰韵,就是這些名稱具有internal鏈接屬性,這和聲明為static的全局名稱的鏈接屬性是相同的熟妓,即名稱的作用域被限制在當(dāng)前文件中雪猪,無(wú)法通過(guò)在另外的文件中使用extern聲明來(lái)進(jìn)行鏈接。如果不提倡使用全局static聲明一個(gè)名稱擁有internal鏈接屬性起愈,則匿名命名空間可以作為一種更好的達(dá)到相同效果的方法浪蹂。
注意:命名空間都是具有external 連接屬性的,只是匿名的命名空間產(chǎn)生的UNIQUE_NAME在別的文件中無(wú)法得到,這個(gè)唯一的名字是不可見(jiàn)的.
C++ 新的標(biāo)準(zhǔn)中提倡使用匿名命名空間,而不推薦使用static,因?yàn)閟tatic用在不同的地方,涵義不同,容易造成混淆.另外,static不能修飾class
總結(jié)
static 常修飾變量或函數(shù) (與匿名空間左右類似,新標(biāo)準(zhǔn)推薦匿名空間)
extern 常修飾變量(對(duì)于函數(shù)沒(méi)必要告材,默認(rèn)是extern的)
詳細(xì)