我已經在C代碼的不一樣地方看到了static
一詞。 這就像C#中的靜態函數/類(實如今對象之間共享)嗎? html
多文件變量做用域示例 git
在這裏,我說明了靜態如何影響多個文件中函數定義的範圍。 程序員
交流電 github
#include <stdio.h> /* Undefined behavior: already defined in main. Binutils 2.24 gives an error and refuses to link. https://stackoverflow.com/questions/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c */ /*int i = 0;*/ /* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */ /*int i;*/ /* OK: extern. Will use the one in main. */ extern int i; /* OK: only visible to this file. */ static int si = 0; void a() { i++; si++; puts("a()"); printf("i = %d\n", i); printf("si = %d\n", si); puts(""); }
main.c 編程
#include <stdio.h> int i = 0; static int si = 0; void a(); void m() { i++; si++; puts("m()"); printf("i = %d\n", i); printf("si = %d\n", si); puts(""); } int main() { m(); m(); a(); a(); return 0; }
GitHub上游 。 數組
編譯並運行: 編輯器
gcc -c a.c -o a.o gcc -c main.c -o main.o gcc -o main main.o a.o
輸出: 函數
m() i = 1 si = 1 m() i = 2 si = 2 a() i = 3 si = 1 a() i = 4 si = 2
解釋 優化
si
有兩個單獨的變量,每一個文件一個 i
一般,範圍越小越好,所以,若是能夠,請始終將變量聲明爲static
。 this
在C編程中,文件一般用於表示「類」,而static
變量表示類的私有靜態成員。
標準怎麼說
C99 N1256草案 6.7.1「存儲類說明符」說, static
是「存儲類說明符」。
6.2.2 / 3「標識符的連接」表示static
表示internal linkage
:
若是對象或函數的文件做用域標識符的聲明包含靜態的存儲類說明符,則該標識符具備內部連接。
6.2.2 / 2說internal linkage
行爲相似於咱們的示例:
在構成整個程序的一組翻譯單元和庫中,帶有外部連接的特定標識符的每一個聲明表示相同的對象或功能。 在一個翻譯單元中,帶有內部連接的標識符的每一個聲明都表示相同的對象或功能。
其中「翻譯單元是通過預處理的源文件。
GCC如何爲ELF(Linux)實施它?
與STB_LOCAL
綁定。
若是咱們編譯:
int i = 0; static int si = 0;
並使用如下命令反彙編符號表:
readelf -s main.o
輸出包含:
Num: Value Size Type Bind Vis Ndx Name 5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si 10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i
所以綁定是它們之間惟一的顯着差別。 Value
只是它們在.bss
節中的偏移量,所以咱們但願它會有所不一樣。
STB_LOCAL
在ELF規範中記錄在http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL本地符號在包含其定義的目標文件以外不可見。 多個文件中可能存在相同名稱的本地符號,而不會互相干擾
這使其成爲表示static
的理想選擇。
沒有靜態的變量是STB_GLOBAL
,規範說:
當連接編輯器組合了幾個可重定位的目標文件時,它不容許名稱相同的STB_GLOBAL符號的多個定義。
這與多個非靜態定義上的連接錯誤一致。
若是使用-O3
啓動優化,則si
符號將從符號表中徹底刪除:不管如何不能從外部使用它。 TODO爲何在沒有優化的狀況下將靜態變量徹底保留在符號表上? 它們能夠用於任何用途嗎? 也許用於調試。
也能夠看看
static
函數: https : //stackoverflow.com/a/30319812/895245 static
與extern
,這與「相反」: 我如何使用extern在源文件之間共享變量? C ++匿名名稱空間
在C ++中,您可能但願使用匿名名稱空間而不是靜態名稱空間,這能夠達到相似的效果,可是會進一步隱藏類型定義: 未命名/匿名名稱空間與靜態函數
這裏沒有涉及另外一種用途,它是數組類型聲明的一部分,用做函數的參數:
int someFunction(char arg[static 10]) { ... }
在這種狀況下,這指定傳遞給此函數的參數必須是char
類型的數組,且其中至少包含10個元素。 有關更多信息,請在此處查看個人問題。
靜態變量值在不一樣的函數調用之間持續存在,而且其做用域僅限於本地塊,而靜態var始終以值0初始化
重要的是要注意,函數中的靜態變量在該函數的第一個條目處被初始化,而且即便在它們的調用完成以後也仍然存在。 在使用遞歸函數的狀況下,靜態變量僅初始化一次,而且在全部遞歸調用中甚至在函數調用完成以後都將持續存在。
若是變量是在函數外部建立的,則意味着程序員只能在已聲明該變量的源文件中使用該變量。
靜態變量是能夠在函數中使用的特殊變量,它能夠保存兩次調用之間的數據,而不會在兩次調用之間刪除數據。 例如:
void func(){ static int count; // If you don't declare its value, the value automatically initializes to zero printf("%d, ", count); ++count; } void main(){ while(true){ func(); } }
輸出:
0、一、二、三、四、5,...