| 關鍵字 | 儲存區域 | 作用域 | 生命週期 | 預設初值 | 連結屬性 |
|---|---|---|---|---|---|
auto (局部預設) | 棧 | 塊內 | 函數調用期間 | 垃圾值 | 無連結 |
static (局部) | 靜態區 (.data/.bss) | 塊內 | 程式全程 | 0 / NULL | 無連結 |
static (全域) | 靜態區 | 檔案內 | 程式全程 | 0 / NULL | 內部連結 |
extern | 靜態區 | 全域 (聲明處可見) | 程式全程 | 0 / NULL | 外部連結 |
register | 寄存器/棧 | 塊內 | 函數調用期間 | 垃圾值 | 無連結 |
| (無關鍵字全域) | 靜態區 | 全域 | 程式全程 | 0 / NULL | 外部連結 |
void func() {
auto int a = 10; // 等同 int a = 10;
// a 佔用棧空間,函數返回即銷毀
}
幾乎不寫 `auto`,C++11 賦予新意(類型推導)。
特性:保持值跨函數調用;僅初始化一次;預設歸零;線程不安全(共享單一實例)。
void counter() {
static int count = 0; // 僅第一次執行初始化
printf("Call %d\n", ++count);
}
int main() { counter(); counter(); counter(); } // 輸出 1, 2, 3
作用:限制連結可見性為**當前編譯單元 (檔案)**。實現封裝,避免符號衝突。
// file1.c
static int internal_id = 100; // 僅 file1 可見
static void helper() { ... } // 僅 file1 可呼叫
// file2.c
// extern int internal_id; // 鏈接錯誤:未定義
// helper(); // 鏈接錯誤
用途:跨檔案共享全域變數/函數。聲明 ≠ 定義。
// global.h
extern int g_count; // 聲明 (無分配空間)
extern void init_sys(); // 函數聲明 (extern 可省略)
// global.c
#include "global.h"
int g_count = 0; // 定義 (分配空間,僅一次)
void init_sys() { g_count = 10; }
// main.c
#include "global.h"
int main() { init_sys(); printf("%d", g_count); }
陷阱:頭檔中 `int g = 0;` 會導致多檔包含產生多重定義錯誤。頭檔只能 `extern`。
建議編譯器:將變數放入 CPU 寄存器加速存取。**不可取址 (`&var` 錯誤)**。現代編譯器 (`-O2`) 自動分配寄存器,`register` 關鍵字多為提示/忽略。
void fast_loop() {
register int i; // 建議放入寄存器
for (i = 0; i < 1000000; i++);
// &i; // 編譯錯誤:address of register variable requested
}
語義:告訴編譯器「此變數值可能在程式不知情下改變(硬體暫存器、中斷服務程式、多執行緒共享變數)」,**每次讀寫必須訪問記憶體**,禁用快取/寄存器優化。
// 硬體暫存器映射
volatile uint32_t *UART_DR = (uint32_t*)0x40004000;
*UART_DR = 'A'; // 寫入發送資料暫存器
// 中斷標誌
volatile int flag = 0;
void ISR() { flag = 1; }
void main_loop() { while (!flag); /* 編譯器不會優化成 while(1) */ }
// const volatile: 僅硬體可寫 (只讀暫存器)
const volatile uint32_t *STATUS_REG = (uint32_t*)0x40004004;
語義:指標 `p` 為**唯一**訪問該記憶體區塊的途徑(無別名)。編譯器可激進優化(向量化、重排、快取)。
// 標準庫 memcpy 原型
void *memcpy(void *restrict dest, const void *restrict src, size_t n);
// 告訴編譯器 dest 和 src 記憶體不重疊,可用 SIMD 指令優化
// 錯誤用法:違反 restrict 承諾 -> 未定義行為
void bad(int *restrict a, int *restrict b) { *a = 1; *b = 2; }
int x; bad(&x, &x); // a 和 b 指向同一地址,違反 restrict