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

C語言中「2+2=5」的記憶體佈局奧秘與編譯器行為分析

     編輯:關於C

現象重現與誤區

網路上流傳一段代碼聲稱能在 C 語言印出「2+2=5」:

int main() {
    char __func_version__[] = "5";
    char b[] = "2", a = 2;
    printf("%d + %s = %s\n", a, b, a + b);
    return 0;
}

實際編譯執行(GCC -O3)並非印出 5,而是不可列印字元。原理是嘗試利用堆疊變數佈局,讓 a+b 正好指向 __func_version__ 的 "5",但編譯器優化、堆疊對齊、變數排序皆不受控,極不可靠。

堆疊佈局實測

加入位址列印觀察 GCC 4.8.2 (-O3) 佈局:

char __func_version__[] = "5";
char b[] = "2", a = 2;
printf("%p %p %p\n", __func_version__, b, &a);
// 輸出:0x7fff504fa920 0x7fff504fa930 0x7fff504fa910

__func_version__ 位址 b 更小(棧向下增長),a+b 只會往高位址偏移,永遠無法觸及前者。整數迴繞也無法精確落在 "5" 位置。

結構體封裝強制佈局

利用 #pragma pack(1) 封裝結構體控制記憶體佈局:

#pragma pack(1)
typedef struct __foo {
    char *b;
    char a;
    char *__func_version__;
} foo;

void print_5_by_struct(void) {
    foo foo_v = {"2", (char)2, "5"};
    printf("%p %p\n", foo_v.__func_version__, foo_v.b);
    printf("%d + %s = %s\n", foo_v.a, foo_v.b, foo_v.a + foo_v.b);
}

成功印出「2+2=5」。結構體成員順序與緊湊排列確保 a+b 落在 __func_version__ 位址。

Clang 編譯器的不同行為

同樣代碼在 Clang 5.1 (LLVM 3.4) -O3 下:

clang -std=c99 -Wall -O3 -g0 -o 5 5.c
// 輸出位址:0x7fff57925936 0x7fff57925934 0x7fff57925933
// 直接印出:2 + 2 = 5

Clang 將變數按宣告順序緊湊排列(__func_version__ 最高、b 中、a 最低),a+b 剛好指向 "5"。展示編譯器對區域變數佈局策略差異巨大。

核心結論

  • 區域變數堆疊佈局完全由編譯器決定,受優化等級、版本、目標架構影響,不可依賴。
  • 「2+2=5」屬未定義行為(UB)利用技巧,僅供娛樂/教學理解堆疊佈局,**絕不可用於生產代碼**。
  • 嚴謹 C 程式設計應:明確初始化、邊界檢查、避免指標算術越界、不依賴記憶體佈局假設。
  • 理解編譯器行為差異(GCC vs Clang)有助於跨平台開發與除錯。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved