| 存儲類型 | 關鍵字 | 作用域 | 生命週期 | 初始化 | 存儲位置 |
|---|---|---|---|---|---|
| 自動變量 | auto (隱式) | 塊作用域 | 函數調用期間 | 不自動初始化 | 棧 |
| 寄存器變量 | register | 塊作用域 | 函數調用期間 | 不自動初始化 | CPU 寄存器 (或棧) |
| 靜態局部變量 | static | 塊作用域 | 程序全周期 | 默認 0,僅初始化一次 | 全局/靜態區 |
| 靜態全局變量 | static | 文件作用域 | 程序全周期 | 默認 0,僅初始化一次 | 全局/靜態區 |
| 外部變量 | extern | 全局 (跨文件) | 程序全周期 | 默認 0 | 全局/靜態區 |
#includeextern int reset(); // 聲明外部函數 extern int next(); extern int last(); extern int sum(int); int i = 1; // 全局變量,初始化為 1 int main() { auto int i, j; // 局部自動變量 i 遮蔽全局 i i = reset(); // 獲取全局 i = 1 for (j = 1; j <= 3; j++) { printf("i=%d\tj=%d\n", i, j); printf("next(i)=%d\n", next()); printf("last(i)=%d\n", last()); printf("sum(i+j)=%d\n", sum(i+j)); } return 0; }
static int i = 10; // 文件級靜態,僅本文件可見
int next() { return i += 1; } // 11, 12, 13...
int last() { return i -= 1; } // 10, 11, 12...
int sum(int i) { // 形式參數 i,與外部無關
static int j = 5; // 函數級靜態,保持狀態
return i = j += i; // 累加邏輯
}
extern int i; // 聲明使用 file1.c 定義的全局 i
int reset() { return i; } // 返回全局 i 的值 (1)
i=1 j=1 next=11 last=10 sum=7 (5+2) i=1 j=2 next=11 last=10 sum=10 (5+3+2? 實際 j 累加: 5+3=8? 需仔細追蹤) i=1 j=3 next=11 last=10 sum=14
關鍵觀察:
auto int i 遮蔽全局 i,但 reset() 訪問的是全局 i (file3.c 經 extern 關聯)file2.c 的 static int i=10 與全局 i 完全隔離sum() 內 static int j=5 跨調用保持值,實現狀態記憶static int file_scope = 42; // 僅當前 .c 文件可見,不參與外部鏈接
解決全局命名衝突,實現文件級封裝。
void counter() {
static int count = 0; // 僅初始化一次,存儲在靜態區
printf("%d\n", ++count);
}
棧變量 → 靜態區,生命週期 = 程序運行期,但作用域仍限於函數內。
static void helper() { ... } // 僅當前文件可調用
同全局變量,限制符號導出,減少鏈接器符號表污染。
®_var 錯誤),寄存器數量有限register 關鍵字多被忽略,僅保留「不可取址」語義避坑指南
| 誤區 | 正確理解 |
|---|---|
| auto 必須顯式寫 | 塊內變量隱式 auto,從不手寫 |
| static 變量線程安全 | 多線程訪問仍需鎖保護 |
| extern 定義變量 | extern 僅聲明,定義需在別處 (無 extern) |
| register 保證進寄存器 | 僅是提示,編譯器可忽略 |