C/C++中的static關(guān)鍵字詳解
static
是 C/C++中的關(guān)鍵字之一,是常見(jiàn)的函數(shù)與變量(C++中還包括類)的修飾符,它常被用來(lái)控制變量的存儲(chǔ)方式和作用范圍。 在眾多高級(jí)語(yǔ)言中都有其作為關(guān)鍵字或函數(shù)出現(xiàn),所以這也是應(yīng)當(dāng)被程序員熟知其各種含義的一個(gè)單詞
我們知道在函數(shù)內(nèi)部定義的變量,當(dāng)程序執(zhí)行到它的定義處時(shí),編譯器為它在棧上分配空間,函數(shù)在棧上分配的空間在此函數(shù)執(zhí)行結(jié)束時(shí)會(huì)釋放掉,這樣就產(chǎn)生了一個(gè)問(wèn)題: 如果想將函數(shù)中此變量的值保存至下一次調(diào)用時(shí),如何實(shí)現(xiàn)? 最容易想到的方法是定義為全局的變量,但定義一個(gè)全局變量有許多缺點(diǎn),最明顯的缺點(diǎn)是破壞了此變量的訪問(wèn)范圍(使得在此函數(shù)中定義的變量,不僅僅只受此函數(shù)控制)。static 關(guān)鍵字則可以很好的解決這個(gè)問(wèn)題。
另外,在 C++ 中,需要一個(gè)數(shù)據(jù)對(duì)象為整個(gè)類而非某個(gè)對(duì)象服務(wù),同時(shí)又力求不破壞類的封裝性,即要求此成員隱藏在類的內(nèi)部,對(duì)外不可見(jiàn)時(shí),可將其定義為靜態(tài)數(shù)據(jù)。
C/C++ 中的 static
這里 static 作用主要影響著變量或函數(shù)的生命周期,作用域,以及存儲(chǔ)位置。
1. 靜態(tài)局部變量
定義在函數(shù)內(nèi)部的變量稱為局部變量(Local Variable),它的作用域僅限于函數(shù)內(nèi)部, 離開(kāi)該函數(shù)后就是無(wú)效的
當(dāng) static 修飾局部變量時(shí):
- 變量的存儲(chǔ)區(qū)域由棧變?yōu)?strong>靜態(tài)常量區(qū)。
- 變量的生命周期由局部變?yōu)?strong>全局。
- 變量的作用域不變。
函數(shù)調(diào)用開(kāi)辟棧幀,函數(shù)中的局部變量在棧上分配存儲(chǔ)空間,當(dāng)函數(shù)執(zhí)行完畢,函數(shù)棧幀銷毀,??臻g由系統(tǒng)回收
而在static
修飾函數(shù)局部變量的時(shí),其修飾的靜態(tài)局部變量只執(zhí)行初始化一次,延長(zhǎng)了局部變量的生命周期,直到程序運(yùn)行結(jié)束以后才釋放,但不改變作用域。
下面用代碼進(jìn)行驗(yàn)證:
#include <stdio.h> void fun() { static int val = 0; //static 修飾局部變量 val++; printf("%d\n", val); } int main() { for (int i = 0; i < 7; i++){ fun(); } return 0; }
沒(méi)有 static
時(shí), 函數(shù)每調(diào)用一次, 變量就會(huì)進(jìn)行一次初始化值為 0,
當(dāng)由 static
修飾時(shí), 初始化語(yǔ)句只會(huì)被執(zhí)行一次所以值會(huì)一直累加。
2. 靜態(tài)全局變量
在所有函數(shù)外部定義的變量稱為全局變量(Global Variable),它的作用域默認(rèn)是整個(gè)程序,也就是所有的源文件,包括 .c 和 .h 文件。
當(dāng) static
修飾全局變量時(shí):
- 變量的存儲(chǔ)區(qū)域在全局?jǐn)?shù)據(jù)區(qū)的靜態(tài)常量區(qū)。
- 變量的作用域由整個(gè)程序變?yōu)?strong>當(dāng)前文件。(extern聲明也不行)
- 變量的生命周期不變。
一個(gè)全局變量被 static
修飾,使全局變量只能在定義變量的當(dāng)前文件使用,不能在其余文件使用,即使 extern
外部聲明也不行。
原因: 屬于文件作用域的聲明在缺省的情況下為 external
鏈接屬性, 如定義個(gè)全局變量int g_a = 1;
, a
的鏈接屬性為external
,而加上 static
會(huì)修改變量的缺省鏈接屬性,改為internal
。
聲明了全局變量 g_a 和 g_b (具有 external
鏈接屬性 )的其他源文件在使用這兩個(gè)變量時(shí)實(shí)際訪問(wèn)的是生命與此處的這兩個(gè)變量;但是 g_c 只能由這個(gè)源文件訪問(wèn),因?yàn)殒溄訉傩?*為internal
。
int g_a = 1; extern int g_b; static int g_c;
代碼驗(yàn)證:
// add.c static int global_val = 27; //static 修飾全局變量 //staticdemo1.c extern global_val; int main() { printf("%d", global_val); return 0; }
不用 static
修飾 global_val
時(shí)的結(jié)果
而使用 static 修飾時(shí),鏈接時(shí)就會(huì)出現(xiàn)鏈接錯(cuò)誤無(wú)法執(zhí)行。
全局變量 與 extren
具有 extrenal
鏈接屬性的實(shí)體在其他語(yǔ)言術(shù)語(yǔ)中稱作全局實(shí)體(global entity ),所有源文件中的函數(shù)均可以訪問(wèn)它。只要變量并非聲明與代碼塊或者函數(shù)定義內(nèi)部,它在缺省的情況下鏈接屬性即為 extrenal
。如果一個(gè)變量聲明與代碼塊內(nèi)部,在它面前添加 extren
關(guān)鍵字將使它使它所引用的是全局變量而非局部變量。
具有鏈接屬性為 extrenal
的實(shí)體總是具有靜態(tài)存儲(chǔ)類型。 全局變量在程序開(kāi)始執(zhí)行前創(chuàng)建,并在整個(gè)執(zhí)行過(guò)程中始終存在。從屬于函數(shù)的局部變量在函數(shù)在函數(shù)開(kāi)始執(zhí)行時(shí)進(jìn)行創(chuàng)建,在函數(shù)執(zhí)行完畢后銷毀,但用于執(zhí)行函數(shù)的機(jī)器指令在程序生命周期內(nèi)一直存在。
使用 extren 進(jìn)行聲明提高代碼的可讀性是良好的編程習(xí)慣。
3. static 修飾函數(shù)
函數(shù)的作用域與全局變量一樣都是整個(gè)程序。
當(dāng) static 修飾函數(shù)時(shí):
函數(shù)的作用域由整個(gè)程序變?yōu)?strong>當(dāng)前文件。(extern聲明也不行)
一個(gè)函數(shù)被 static
修飾,使函數(shù)只能在定義的源文件使用,不能在其余文件使用,即使 extern
外部聲明也不行。(同static
修飾全局變量)
如果我們將函數(shù)聲明為
static
,就會(huì)把它的鏈接屬性從external
,改為internal
,這樣將使得其他源文件不能訪問(wèn)這個(gè)函數(shù);對(duì)于函數(shù)而言,存儲(chǔ)類型不是問(wèn)題,因?yàn)榇a總是存儲(chǔ)在只讀的代碼區(qū)中。
// add.c static int add(int a, int b) { return a + b; } //staticdemo1.c extern add(int a, int b); int main() { printf("%d", add(10, 20)); return 0; }
這里直接看結(jié)果:
沒(méi)有 static
修飾:
被 static
修飾:報(bào)了與修飾全局變量時(shí)同樣的鏈接錯(cuò)誤。
C++的 static 成員
聲明為static
的類成員稱為類的靜態(tài)成員,用static
修飾的成員變量,稱之為靜態(tài)成員變量;用static
修飾的 成員函數(shù),稱之為靜態(tài)成員函數(shù)。
注:靜態(tài)的成員變量一定要在類外進(jìn)行初始化
class A { public : A(){ //構(gòu)造函數(shù) _count++; } A(const A& y){ _count++; } static int GetCount(){ //靜態(tài)成員函數(shù) return _count; } public: int a; //靜態(tài)成員變量--》在類中的是聲明要在類外進(jìn)行定義 static int _count; }; }; int A::_count = 0; //靜態(tài)變量 _count 定義 void TestA() { cout << A::GetCount() << endl; // 類靜態(tài)成員通過(guò) 類名::靜態(tài)成員 來(lái)訪問(wèn) A a1, a2; A a3(a1); cout << A::GetCount() << endl; }
靜態(tài)成員變量
1.靜態(tài)成員變量必須在類外進(jìn)行定義定義時(shí)不用加 static
,類中只是聲明
2.靜態(tài)成員變量為所有類對(duì)象所共享,并沒(méi)有包含在具體的對(duì)象中。
所以并不影響 sizeof()
大小
3.靜態(tài)成員變量的訪問(wèn):
- 類名::靜態(tài)成員變量名
- 對(duì)象.靜態(tài)成員變量名。
cout << A::_count << endl; cout << a1._count << endl;
類的對(duì)象可以使用靜態(tài)成員函數(shù)和非靜態(tài)成員函數(shù)。
注:靜態(tài)成員變量也受訪問(wèn)限定符(public、protected、private
)的限制。 所以私有的仍要通過(guò)類成員函數(shù)接口來(lái)進(jìn)行訪問(wèn),可以在通過(guò)類中公有的成員函數(shù)進(jìn)行訪問(wèn),
cout << A::GetCount() << endl;
但這種方式調(diào)用獲取靜態(tài)成員變量必須由靜態(tài)成員函數(shù)訪問(wèn),不能通過(guò)類名來(lái)調(diào)用類的非靜態(tài)成員函數(shù),否則就會(huì)出錯(cuò)
靜態(tài)成員函數(shù)
1.靜態(tài)成員函數(shù)沒(méi)有隱藏的 this
指針,不能訪問(wèn)非靜態(tài)成員(變量、 函數(shù))!
因?yàn)殪o態(tài)成員函數(shù)沒(méi)有隱藏的 this
指針?biāo)砸膊荒芏x成const
成員函數(shù)(const 本質(zhì)就是修飾隱藏參數(shù)this )
2.靜態(tài)成員函數(shù)不能調(diào)用非靜態(tài)成員函數(shù)。
3.非靜態(tài)成員函數(shù)可以調(diào)用靜態(tài)成員函數(shù)。
static void fun(){ _count = 0; } int GetCount(){ //cout << this << endl; fun(); return _count; }
總結(jié):
(1) 靜態(tài)成員變量使用前必須先初始化(在類外定義),如:int A::_count = 0;
(2) 靜態(tài)成員變量為所有類對(duì)象所共享,也受訪問(wèn)限定符(public、protected、private
)的限制
(3) 靜態(tài)成員函數(shù)不能調(diào)用非靜態(tài)成員函數(shù),非靜態(tài)成員函數(shù)可以調(diào)用靜態(tài)成員函數(shù)
(4) 靜態(tài)成員函數(shù)沒(méi)有隱藏的 this
指針
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Cocos2d-x保存用戶游戲數(shù)據(jù)之XML文件是否存在問(wèn)題判斷方法
這篇文章主要介紹了Cocos2d-x保存用戶游戲數(shù)據(jù)之XML文件是否存在問(wèn)題判斷方法,請(qǐng)注意代碼中包含大量注釋,需要的朋友可以參考下2014-09-09C++ 中cerr和cout的區(qū)別實(shí)例詳解
這篇文章主要介紹了C++ 中cerr和cout的區(qū)別實(shí)例詳解的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09面試常見(jiàn)問(wèn)題之C語(yǔ)言與C++的區(qū)別問(wèn)題
在C中,用static修飾的變量或函數(shù),主要用來(lái)說(shuō)明這個(gè)變量或函數(shù)只能在本文件代碼塊中訪問(wèn),而文件外部的代碼無(wú)權(quán)訪問(wèn),今天重點(diǎn)給大家介紹面試中常見(jiàn)的C語(yǔ)言與C++區(qū)別的問(wèn)題,感興趣的朋友跟隨小編一起看看吧2021-05-05C++中一維數(shù)組與指針的關(guān)系詳細(xì)總結(jié)
以下是對(duì)C++中一維數(shù)組與指針的關(guān)系進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過(guò)來(lái)參考下2013-09-09C語(yǔ)言接口與實(shí)現(xiàn)方法實(shí)例詳解
這篇文章主要介紹了C語(yǔ)言接口與實(shí)現(xiàn)方法,包括接口的概念、實(shí)現(xiàn)方法及抽象數(shù)據(jù)類型等,并配合實(shí)例予以說(shuō)明,需要的朋友可以參考下2014-09-09深入探討C++ OpenCV如何實(shí)現(xiàn)圖像矯正
這篇文章主要為大家詳細(xì)介紹了C++ OpenCV如何實(shí)現(xiàn)簡(jiǎn)單的圖像矯正功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03C++11新特性中auto 和 decltype 區(qū)別和聯(lián)系
這篇文章主要介紹了C++11新特性中auto 和 decltype 區(qū)別和聯(lián)系的相關(guān)資料,需要的朋友可以參考下2017-01-01