[C/C++]在標頭檔案中使用static定義變數意味著什麼
宣告:本文乃轉載文章,轉載出處:https://www.cnblogs.com/computer1-2-3/p/6088388.html
看到有一位同學在標頭檔案中這麼寫:
1 static const wchar_t* g_str1 = … 2 static const wchar_t* g_str2 = …
這種定義變數的方式我從來沒有見過,而且它還能順利通過編譯,於是我很想知道編譯器是如何處理這種變數定義的。
定義全域性變數時使用static,意味著該變數的作用域只限於定義它的原始檔中,其它原始檔不能訪問。既然這種定義方式出現在標頭檔案中,那麼可以很自然地推測:包含了該標頭檔案的所有原始檔中都定義了這些變數,即該標頭檔案被包含了多少次,這些變數就定義了多少次。
假如將上面兩行程式碼的static去掉,編譯的時候就會出現變數重定義的錯誤,這進一步證實了上面的推測,因為沒有static的話變數的作用域是全域性的,定義了兩個以上的同名變數就會出現該錯誤。
推測終究是推測,要真正證實這個推測還要通過寫程式碼來驗證。驗證的方式是:在標頭檔案中使用static定義變數,在多個原始檔中包含該標頭檔案,然後在每個原始檔中輸出變數的地址,同時在一個原始檔中改變變數的值並輸出,在另一個原始檔中也輸出。如果每個原始檔的輸出都不同,則推測得證;否則推測是錯誤的。
下面是定義變數的標頭檔案的程式碼:
1 //Header.h 2 #pragma once 3 4 static intg_int = 3;
接下來在另一個頭檔案中宣告兩個測試函式:
1 //Functions.h 2 #pragma once 3 4 void TestSource1(); 5 void TestSource2();
分別在兩個原始檔中定義這兩個測試函式:
1 //Source1.cpp 2 #include <stdio.h> 3 #include "Header.h" 4 5 void TestSource1() { 6 7 wprintf(L"g_int's address in Source1.cpp: %08x\n", &g_int); 8 g_int = 5; 9 wprintf(L"g_int's value in Source1.cpp: %d\n", g_int); 10 }
1 //Source2.cpp 2 #include <stdio.h> 3 #include "Header.h" 4 5 void TestSource2() { 6 7 wprintf(L"g_int's address in Source2.cpp: %08x\n", &g_int); 8 wprintf(L"g_int's value in Source2.cpp: %d\n", g_int); 9 }
最後在main函式中呼叫這兩個測試函式:
1 //Main.cpp 2 #include "Functions.h" 3 4 int wmain() { 5 6 TestSource1(); 7 TestSource2(); 8 }
執行該程式:
可以看到,雖然在程式碼中好像使用了相同的變數,但是實際上使用的是不同的變數,在每個原始檔中都有單獨的變數。所以,在標頭檔案中定義static變數會造成變數多次定義,造成記憶體空間的浪費,而且也不是真正的全域性變數。應該避免使用這種定義方式。
作為對比,下面使用正確的方式來定義全域性變數:
1 //Header.h 2 #pragma once 3 4 extern int g_int;
1 //Source1.cpp 2 #include <stdio.h> 3 #include "Header.h" 4 5 int g_int = 3; 6 7 void TestSource1() { 8 9 wprintf(L"g_int's address in Source1.cpp: %08x\n", &g_int); 10 g_int = 5; 11 wprintf(L"g_int's value in Source1.cpp: %d\n", g_int); 12 13 }
其它檔案不變。
執行程式:
可以看到,這次兩個原始檔中使用的都是同一個變數。要注意的是,使用extern宣告變數時不能帶有初始值,否則仍然屬於變數定義,會出現變數重定義的錯誤。