首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言細節深度解析:段錯誤、類型提升與 sizeof('A') 的陷阱

     編輯:關於C語言

C 語言細節深度解析:段錯誤、類型提升與 sizeof('A') 的陷阱

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;
}

知識點 1:段錯誤 vs 總線錯誤

錯誤類型觸發原因典型場景
段錯誤訪問未映射或無權限的記憶體頁空指針解引用、棧溢出、訪問已釋放堆內存
總線錯誤CPU 無法完成硬體層面的記憶體存取非對齊訪問(如上例 int* 指向奇數地址)、硬體故障

代碼中 int *p = (int *)&(u.a[1]) 強制將 char* 轉為 int*,導致 p 指向地址 &u + 1,這在要求 4 字節對齊的架構(SPARC、ARM 某些模式)上會觸發總線錯誤;而在 x86/x64 上 CPU 自動處理非對齊訪問,程序能正常運行,但效率略低。

知識點 2:sizeof('A') 為什麼是 4?

在 C 標準中,字符常量(如 'A')的類型是 int,而非 char。因此 sizeof('A') == sizeof(int),在 32/64 位主流平台上均為 4 字節。這與 C++ 不同(C++ 中 'A' 類型為 char,sizeof 為 1)。

知識點 3:char 運算發生的整型提升與溢出

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)。

運行結果速覽

程序輸出截圖

總結

  • 段錯誤是記憶體保護機制;總線錯誤是硬體總線層面的非法存取。
  • C 語言字符常量是 int,sizeof('A') 等於 sizeof(int)。
  • char 參與算術運算會先整型提升為 int,賦值回 char 時可能溢出。

掌握這些細節,能讓你在調試疑難崩潰、編寫跨平台代碼時更有底氣。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved