if/else)定義的同名 static 變量互不干擾#include <stdio.h>
void func(int i) {
if ((i & 0x01) == 1) { // 奇數分支
static int j = 1; // 僅初始化一次
j++;
printf("i=%d, j=%d.\n", i, j);
} else { // 偶數分支
static int j = 0; // 另一個獨立變量
j++;
printf("\ti=%d, j=%d.\n", i, j);
}
/* printf("j=%d", j); // 編譯錯誤:j 不在作用域內 */
}
int main(void) {
for (int i = 0; i < 10; ++i)
func(i);
return 0;
}
i=0, j=1.
i=1, j=2.
i=2, j=2.
i=3, j=3.
i=4, j=3.
i=5, j=4.
i=6, j=4.
i=7, j=5.
i=8, j=5.
i=9, j=6.
| i | 分支 | 該 static j 初始值 | 遞增後值 | 說明 |
|---|---|---|---|---|
| 0 | else | 0 | 1 | 首次進入 else,j=0 初始化 |
| 1 | if | 1 | 2 | 首次進入 if,j=1 初始化 |
| 2 | else | 1 | 2 | else 的 j 保留上次值 1 |
| 3 | if | 2 | 3 | if 的 j 保留上次值 2 |
| ... | ... | ... | ... | 兩個 j 完全獨立累加 |
| 類別 | 關鍵字 | 作用域 | 生命週期 | 連結屬性 | 典型用途 |
|---|---|---|---|---|---|
| 全域靜態 | 檔案層級 static | 檔案內(內部連結) | 程式全期 | 內部連結 | 模組私有狀態、單例 |
| 函數靜態 | 函數層級 static | 函數內(區域) | 程式全期 | 無連結 | 計數器、快取、延遲初始化 |
| 塊級靜態 | 區塊層級 static | 區塊內({ }) | 程式全期 | 無連結 | 分支獨立狀態、稀有場景 |
Config *get_config(void) {
static Config cfg = {0}; // 零初始化
static bool inited = false;
if (!inited) {
load_config(&cfg); // 僅首次調用執行
inited = true;
}
return &cfg;
}
void api_call(void) {
static unsigned long cnt = 0;
if (++cnt % 1000 == 0)
log_info("API called %lu times", cnt);
}
char *get_temp_buf(size_t need) {
static char *buf = NULL;
static size_t cap = 0;
if (need > cap) {
cap = need;
buf = realloc(buf, cap); // 僅增不減,生命週期至程式結束
}
return buf;
}
誤區:「
static變量是線程安全的。」
事實:不是。多執行緒同時首次初始化或並發讀寫會有競態條件,需配合_Atomic、pthread_once、call_once或鎖。
誤區:「塊級
static變量在 C++ 中會在首次進入時執行建構函數,線程安全(C++11)。」
事實:僅限 C++。C 語言無此保證,且 C 標準未要求線程安全初始化。
static 就不用函數級;能用函數級就不用檔案級;能用檔案級就不用全域 externs_ 前綴區分靜態變量(如 s_call_count)static 賦予區域變量「全局生命、局部視野」的雙重特性。理解其一次初始化、跨調用保值、作用域隔離三大鐵律,能讓你在需要「函數記憶」時精準出手,避免全域變量污染命名空間。