要面試了,復習一下c++的語言細節,才發現自己差的還很多。
static int i1=1; static int i2=1; int i3; static int i4; int main() { static int i5=1; int i6=1; int i7; cout<<&i1<<" "<<i1<<endl; cout<<&i2<<" "<<i2<<endl; cout<<&i3<<" "<<i3<<endl; cout<<&i4<<" "<<i4<<endl; cout<<&i5<<" "<<i5<<endl; cout<<&i6<<" "<<i6<<endl; cout<<&i7<<" "<<i7<<endl; getchar(); }
輸出:
首先說值:
普通/static全局變量(i3)默認初始化為0,普通局部變量初始值未定義(i7)
static局部變量即靜態局部變量,也會初始化為0
再說內存存儲位置:
先放個進程的內存圖:
其中未初始化+初始化區域就是靜態區。注意靜態區和常量區還不一樣,常量比如:int a=1;的1。或者char* x="123";的“123”。
對應這兩張圖來看就很清晰了
好,下面進入主題:
全局變量都在靜態變量區,不管是不是static
注意未初始化的和未初始化的不在一起的!證據如下,其中第一行的都是帶初始化的,第二行不帶初始化的,明顯可見未初始化的bss段地址比已經初始化的數據段地址更大,更靠上:
普通局部變量在棧區/堆區,static局部變量在靜態變量區。
static的不同用法:
1.static全局變量/函數,因為函數肯定是全局的了,所以這倆捏一起說。
只有一個用途:不讓其他cpp使用自己,即限制作用域為所在的cpp。如果不帶static,其他cpp可以extern修飾進而引用。
所以假設a.cpp里有一個函數f。
如果我們想讓其他cpp引用這個f函數。那么我們應該把f的聲明加入到a.cpp的頭文件並且聲明時不要加static,這樣會導致每個包含a.h的cpp都有一份該函數f的副本,大大增加編譯效率!當然這個問題回頭另外寫一篇博客,就先點到為止。另外永遠不要在頭文件中定義變量!
如果我們不想讓其他cpp引用f函數,則我們直接在f的定義前加上static修飾,這樣其他cpp就看不到f函數了(即使包含a頭文件的情況下也是看不到的)。
2.static局部變量,如:
void f(){ static int cnt=0;cnt++; }
這個函數調用幾次,cnt就等於幾。
static局部變量和全局變量一起存在靜態變量區,二者唯一的區別就是:static局部變量作用域只限於所在的函數,但到達函數以外時並不會釋放,而是會保持已有的值繼續等待下次調用。
static局部變量只會初始化一次!直到cpp退出才會釋放。
3.類中的static成員變量(類的靜態成員變量):
static成員變量分配在靜態區。
在所有該類的實例(對象)中只存在一個副本,所有對象共享一個該靜態變量。
類的靜態成員變量需要在類中聲明,類外定義,例子如下:
class A{ static int x; }; int A::x=1;
4.類中的static成員函數:
Static修飾的成員函數,在代碼區分配內存。只能調用靜態成員變量,別的和普通成員函數區別不大。
概括來說:類的靜態成員函數、變量的存儲位置不在類里,所以也就理所當然的沒有this指針。所以靜態成員函數無法調用普通成員變量也就合理了(因為沒有this指針,根本找不到相應的變量位置!)。
由於二者都與類綁定,而不與特定對象綁定,所以二者可以除了可以通過對象訪問外,還可以通過類名訪問(A:: f();)。
另外注意:靜態成員函數不能加const限定,可能是因為靜態成員函數本身就不會改變類內部數據。