轉載: http://www.cnblogs.com/catch/p/4314256.html
什麼時候初始化
根據 C++ 标準,全局變量的初始化要在 main 函數執行前完成,常識無疑,但是這個說法有點含糊,main 函數執行前到底具體是什麼時候呢?是編譯時還是運作時?答案是既有編譯時,也可能會有運作時(seriously), 從語言的層面來說,全局變量的初始化可以劃分為以下兩個階段(c++11 N3690 3.6.2):
- static initialization: 靜态初始化指的是用常量來對變量進行初始化,主要包括 zero initialization 和 const initialization,靜态初始化在程式加載的過程中完成,對簡單類型(内建類型,POD等)來說,從具體實作上看,zero initialization 的變量會被儲存在 bss 段,const initialization 的變量則放在 data 段内,程式加載即可完成初始化,這和 c 語言裡的全局變量初始化基本是一緻的。
- dynamic initialization:動态初始化主要是指需要經過函數調用才能完成的初始化,比如說:
,或者是複雜類型(類)的初始化(需要調用構造函數)等。這些變量的初始化會在 main 函數執行前由運作時調用相應的代碼進而得以進行(函數内的 static 變量除外)。int a = foo()
http://4byte.cn/question/2070807/when-static-or-dynamic-initialization.html

Formally, C++ initializes such variables in three phases:
1. Zero initialization
2. Static initialization
3. Dynamic initialization
The language also distinguishes between variables which require dynamic initialization, and those which require static initialization: all static objects (objects with static lifetime) are first zero initialized, then objects with static initialization are initialized, and then dynamic initialization occurs.
As a simple first approximation, dynamic initialization means that some code must be executed; typically, static initialization doesn't. Thus:
extern int f();
int g1 = 42; // static initialization
int g2 = f(); // dynamic initialization
Another approximization would be that static initialization is what C supports (for variables with static lifetime), dynamic everything else.
How the compiler does this depends, of course, on the initialization, but on disk based systems, where the executable is loaded into memory from disk, the values for static initialization are part of the image on disk, and loaded directly by the system from the disk. On a classical Unix system, global variables would be divided into three "segments":
需要明确的是:靜态初始化執行先于動态初始化! 隻有當所有靜态初始化執行完畢,動态初始化才會執行。顯然,這樣的設計是很直覺的,能靜态初始化的變量,它的初始值都是在編譯時就能确定,是以可以直接 hard code 到生成的代碼裡,而動态初始化需要在運作時執行相應的動作才能進行,是以,靜态初始化先于動态初始化是必然的。
初始化的順序
對于出現在同一個編譯單元内的全局變量來說,它們初始化的順序與他們聲明的順序是一緻的(銷毀的順序則反過來),而對于不同編譯單元間的全局變量,c++ 标準并沒有明确規定它們之間的初始化(銷毀)順序應該怎樣,是以實作上完全由編譯器自己決定,一個比較普遍的認識是:不同編譯單元間的全局變量的初始化順序是不固定的,哪怕對同一個編譯器,同一份代碼來說,任意兩次編譯的結果都有可能不一樣[1]。
是以,一個很自然的問題就是,如果不同編譯單元間的全局變量互相引用了怎麼辦?
當然,最好的解決方法是盡可能的避免這種情況(防治勝于治療嘛),因為一般來說,如果出現了全局變量引用全局變量的窘況,那多半是程式本身的設計出了問題,此時最應該做的是回頭重新思考和修改程式的結構與實作,而不是急着窮盡技巧來給錯誤的設計打更新檔。
http://blog.csdn.net/wingfiring/article/details/498242
http://docs.linuxtone.org/ebooks/C&CPP/c/ch03s04.html
http://coolshell.cn/articles/10115.html
靜态變量的初始化時機:
全局變量、檔案域的靜态變量和類的靜态成員變量在main執行之前的靜态初始化過程中配置設定記憶體并初始化;局部靜态變量(一般為函數内的靜态變量)在第一次使用時配置設定記憶體并初始化。這裡的變量包含内置資料類型和自定義類型的對象。
靜态變量的作用域是目前源檔案,全局變量的作用域是整個可執行程式。 值得注意的是:
- 如果在頭檔案定義全局變量,在預編譯期間
的頭檔案會被拷貝進源檔案中,編譯器是不知道頭檔案的。#include
- 雖然全局變量是全局作用域,但需要
關鍵字來聲明以通過編譯。因為C++是強類型語言,編譯時需要根據變量聲明做類型檢查。extern
非靜态的局部變量: 生存周期隻是在函數調用期間,函數調用結束就結束了,下一次調用需要重新配置設定空間和重新初始化。
全局變量和靜态變量都是存儲在全局資料區。全局變量和靜态變量如果沒有手工初始化,則由編譯器初始化為0。局部變量的值不可知。
代碼區 |
全局資料區 |
堆區 |
棧區 |
不要寫依靠于初始化順序的代碼,在多線程環境中可能會出問題。
static作用(修飾函數、局部變量、全局變量)
在C語言中,static的字面意思很容易把我們導入歧途,其實它的作用有三條。
(1)先來介紹它的第一條也是最重要的一條:隐藏。
當我們同時編譯多個檔案時,所有未加static字首的全局變量和函數都具有全局可見性。為了解這句話,我舉例來說明。我們要同時編譯兩個源檔案,一個是a.c,另一個是main.c。
下面是a.c的内容
char a = 'A'; // global variable
void msg()
{
printf("Hello\n");
}
下面是main.c的内容
int main( void)
{
extern char a; // extern variable must be declared before use
printf("%c ", a);
( void)msg();
return 0;
}
程式的運作結果是:
A Hello
你可能會問:為什麼在a.c中定義的全局變量a和函數msg能在main.c中使用?前面說過,所有未加static字首的全局變量和函數都具有全局可見性,其它的源檔案也能通路。此例中,a是全局變量,msg是函數,并且都沒有加static字首,是以對于另外的源檔案main.c是可見的。
如果加了static,就會對其它源檔案隐藏。例如在a和msg的定義前加上static,main.c就看不到它們了。利用這一特性可以在不同的檔案中定義同名函數和同名變量,而不必擔心命名沖突。Static可以用作函數和變量的字首,對于函數來講,static的作用僅限于隐藏,而對于變量,static還有下面兩個作用。
(2)static的第二個作用是保持變量内容的持久。存儲在靜态資料區的變量會在程式剛開始運作時就完成初始化,也是唯一的一次初始化。共有兩種變量存儲在靜态存儲區:全局變量和static變量,隻不過和全局變量比起來,static可以控制變量的可見範圍,說到底static還是用來隐藏的。雖然這種用法不常見,但我還是舉一個例子。
#include
int fun( void){
static int count = 10; // 事實上此指派語句從來沒有執行過
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;
}
程式的運作結果是:
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的第三個作用是預設初始化為0。其實全局變量也具備這一屬性,因為全局變量也存儲在靜态資料區。在靜态資料區,記憶體中所有的位元組預設值都是0x00,某些時候這一特點可以減少程式員的工作量。比如初始化一個稀疏矩陣,我們可以一個一個地把所有元素都置0,然後把不是0的幾個元素指派。如果定義成靜态的,就省去了一開始置0的操作。再比如要把一個字元數組當字元串來用,但又覺得每次在字元數組末尾加’\0’太麻煩。如果把字元串定義成靜态的,就省去了這個麻煩,因為那裡本來就是’\0’。不妨做個小實驗驗證一下。
#include
int a;
int main( void)
{
int i;
static char str[10];
printf("integer: %d; string: (begin)%s(end)", a, str);
return 0;
}
程式的運作結果如下
integer: 0; string: (begin)(end)
最後對static的三條作用做一句話總結。首先static的最主要功能是隐藏,其次因為static變量存放在靜态存儲區,是以它具備持久性和預設值0。
以上内容出自部落格園Mr. Write之手,寫的相當清晰易懂,存檔友善複習。原文位址:http://www.cnblogs.com/dc10101/archive/2007/08/22/865556.html
下面是中興通訊2012校招筆試題的一道問答題:
1. static全局變量與普通的全局變量有什麼差別 ?
全局變量(外部變量)的說明之前再冠以static 就構成了靜态的全局變量。
全局變量本身就是靜态存儲方式, 靜态全局變量當然也是靜态存儲方式。 這兩者在存儲方式上并無不同。
這兩者的差別在于非靜态全局變量的作用域是整個源程式, 當一個源程式由多個源檔案組成時,非靜态的全局變量在各個源檔案中都是有效的。 而靜态全局變量則限制了其作用域, 即隻在定義該變量的源檔案内有效, 在同一源程式的其它源檔案中不能使用它。由于靜态全局變量的作用域局限于一個源檔案内,隻能為該源檔案内的函數公用,是以可以避免在其它源檔案中引起錯誤。
static全局變量隻初使化一次,防止在其他檔案單元中被引用;
2. static局部變量和普通局部變量有什麼差別 ?
把局部變量改變為靜态變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜态變量後是改變了它的作用域,限制了它的使用範圍。
static局部變量隻被初始化一次,下一次依據上一次結果值;
3. static函數與普通函數有什麼差別?
static函數與普通函數作用域不同,僅在本檔案。隻在目前源檔案中使用的函數應該說明為内部函數(static修飾的函數),内部函數應該在目前源檔案中說明和定義。對于可在目前源檔案以外使用的函數,應該在一個頭檔案中說明,要使用這些函數的源檔案要包含這個頭檔案.
static函數在記憶體中隻有一份,普通函數在每個被調用中維持一份拷貝