C 語言看似簡單,實則暗藏許多「細節決定成敗」的陷阱。本文通過一個完整示例程序,深入剖析段錯誤與總線錯誤的區別、字符常量的類型提升規則、以及 sizeof('A') 為何等於 sizeof(int) 這三個核心知識點。
#include <stdio.h>
int main() {
union test {
char a[10];
int b;
} u;
/* ---------- 1. 總線錯誤 vs 段錯誤 ---------- */
int *p = (int *)&(u.a[1]); // 故意讓 int* 指向非 4 字節對齊地址
*p = 17; // 某些架構觸發總線錯誤,x86 通常能跑通
#if 0
int *q = 0; // 空指針解引用
*q = 1; // 必定觸發段錯誤
#endif
/* ---------- 2. sizeof('A') 與類型提升 ---------- */
printf("%zu\n", sizeof 'A'); // 輸出 4(視 int 寬度而定)
/* ---------- 3. char 相加溢出 ---------- */
char c1 = 'a', c2 = 'b'; // 97, 98
char c3 = c1 + c2; // 195 超過 signed char 範圍 → 溢出
printf("%d %d %d\n", c1, c2, c3); // 輸出:97 98 -61
return 0;
}
| 錯誤類型 | 觸發原因 | 典型場景 |
|---|---|---|
| 段錯誤 | 訪問未映射或無權限的記憶體頁 | 空指針解引用、棧溢出、訪問已釋放堆內存 |
| 總線錯誤 | CPU 無法完成硬體層面的記憶體存取 | 非對齊訪問(如上例 int* 指向奇數地址)、硬體故障 |
代碼中 int *p = (int *)&(u.a[1]) 強制將 char* 轉為 int*,導致 p 指向地址 &u + 1,這在要求 4 字節對齊的架構(SPARC、ARM 某些模式)上會觸發總線錯誤;而在 x86/x64 上 CPU 自動處理非對齊訪問,程序能正常運行,但效率略低。
在 C 標準中,字符常量(如 'A')的類型是 int,而非 char。因此 sizeof('A') == sizeof(int),在 32/64 位主流平台上均為 4 字節。這與 C++ 不同(C++ 中 'A' 類型為 char,sizeof 為 1)。
char c1 = 'a'; // 97
char c2 = 'b'; // 98
char c3 = c1 + c2; // 1. 整型提升:c1、c2 先轉為 int 相加 → 195
// 2. 賦值給 char:195 超過 signed char 最大值 127
// 3. 截斷/補碼:195 - 256 = -61
printf("%d", c3); // 輸出 -61
避坑指南:若需保留完整結果,應用 int 或 unsigned char 接收;或顯式轉型 (unsigned char)(c1 + c2)。

int,sizeof('A') 等於 sizeof(int)。char 參與算術運算會先整型提升為 int,賦值回 char 時可能溢出。掌握這些細節,能讓你在調試疑難崩潰、編寫跨平台代碼時更有底氣。