C 語言關鍵字看似簡單,實則暗藏玄機。本文深度解析 `register`、`volatile`、`sizeof`、`const`、`typedef`、`union`、`static`、`unsigned` 等核心關鍵字的語義、陷阱與最佳實踐。
register int fast_counter; // 建議編譯器放入寄存器
volatile int hardware_reg; // 硬件寄存器映射
volatile int interrupt_flag; // 中斷服務程序修改的標志
const volatile int read_only_reg; // 唯讀硬件寄存器
int i = 0;
sizeof(i); // ✓ 運算元為表達式,括號可省
sizeof int; // ✗ 運算元為類型,括號必須保留
sizeof(int); // ✓ 類型需括號
char a[10][10];
char *p = a[0];
sizeof(a); // 100 (char[10][10])
sizeof(a[0]); // 10 (char[10])
sizeof(a[0][0]); // 1 (char)
sizeof(p); // 4/8 (指針大小)
sizeof(*p); // 1 (char)
void func(char arr[100]) { // 等價於 char *arr
sizeof(arr); // 4/8 (指針),而非 100!
}
鐵律:函數參數聲明為數組,實際傳遞的是指針,`sizeof` 返回指針大小。
| 表達式 | sizeof | strlen |
|---|---|---|
| `"hello"` | 6 (含 `\0`) | 5 |
| `char s[] = "hello"` | 6 | 5 |
| `char *p = "hello"` | 4/8 (指針) | 5 |
struct { char c; int i; } s1; // sizeof = 8 (對齊填充 3 字節)
struct { int i; char c; } s2; // sizeof = 8 (填充 3 字節在尾部)
#pragma pack(1)
struct { char c; int i; } s3; // sizeof = 5 (無填充)
對齊規則:成員偏移為 `min(sizeof(member), #pragma pack值)` 的倍數;結構體總大小為最大對齊數的倍數。
「const 修飾其右側最近的類型」(若無右側類型,修飾左側)。
| 聲明 | 含義 | 可修改指針 | 可修改值 |
|---|---|---|---|
| `const int *p` / `int const *p` | 指向常量的指針 | 是 | 否 |
| `int * const p` | 常指針(指針本身不可變) | 否 | 是 |
| `const int * const p` | 指向常量的常指針 | 否 | 否 |
| `int const * const p` | 同上 | 否 | 否 |
void func(const int *p); // 不修改指向內容
void func(int * const p); // 不修改指針本身(無意義,參數傳值)
void func(const int * const p); // 兩者皆不修改
// typedef:語義層面,編譯期處理
typedef int *IntPtr;
IntPtr a, b; // a、b 都是 int*
// #define:文本替換,預處理期
#define IntPtr int *
IntPtr a, b; // a 是 int*,b 是 int(展開為 int *a, b;)
// 函數指針類型
typedef void (*SignalHandler)(int);
SignalHandler handlers[32];
// 避免聲明混淆
// int *p, q; // p 是指針,q 是 int
// typedef int *IntPtr; IntPtr p, q; // 兩者都是指針
// 經典端序檢測
int check_endian(void) {
union { int i; char c; } u;
u.i = 1;
return u.c == 1; // 1 = 小端, 0 = 大端
}
| 語境 | 作用 | 生命週期 | 作用域/可見性 |
|---|---|---|---|
| 函數內局部 | 保持值跨調用 | 程序全期 | 僅函數內 |
| 文件域變量 | 內部鏈接 | 程序全期 | 僅本文件(編譯單元) |
| 文件域函數 | 內部鏈接 | 程序全期 | 僅本文件 |
void func(void) {
static int count = 0; // 僅初始化一次!
printf("%d ", count++);
}
int main() { func(); func(); func(); } // 輸出: 0 1 2
unsigned int u = 10;
int i = -1;
if (u > i) // i 隱式轉換為 unsigned -> 極大正數,條件為假!
puts("u > i");
else
puts("u <= i"); // 輸出此行