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

深入研究 C 語言(二):內存佈局、棧幀、調用約定與結構體傳遞的汇編級剖析

     編輯:關於C語言

實驗環境

Turbo C 2.0 (16位實模式),Debug 反汇編觀察。段寄存器:CS(代碼)、DS(數據)、SS(棧)、ES(附加)。

程序一:全局/局部變量、參數、返回值存儲位置

int n=0, a, b, c;
int f1() { return 1; }
int f2(int x, int y) { int c; return x+y; }
int f3(int x, int y) { return x+y; } // 遠調用
void main() { n = f1(); a = f2(1,2); b = f3(3,4); }

關鍵觀察

實體存儲段地址形式生命週期
全局變量 n,a,b,cDS (數據段)DS:offset (如 DS:01A6)程序啟動分配,結束釋放
局部變量 (f2 中 c)SS (棧段)BP+offset (如 BP-2)函數調用分配,返回釋放
參數 x,ySS (棧段)BP+offset (壓棧順序:右至左)調用者壓棧,調用者清棧 (CDECL)
返回值AX 寄存器16位值直接放 AX調用約定規定

棧幀建立與銷毀 (f2)

; 調用者
push 2      ; 參數 y (右至左)
push 1      ; 參數 x
call f2
add sp, 4   ; 調用者清棧

; f2 入口
push bp
mov bp, sp
sub sp, 2   ; 分配局部變量 c 空間
; ... 訪問參數 [bp+4], [bp+6]
; 返回值放入 AX
mov sp, bp
pop bp
ret

近調用 vs 遠調用

  • f1:call near ptr (段內),返回 ret (僅彈 IP)。
  • f3:call far ptr (段間),返回 retf (彈 CS:IP)。
    區別在於函數聲明是否帶 far 關鍵字或編譯模型 (Large/Huge)。

程序二:優化器對變量存儲的影響

int a=0; void f() { int n=2; n++; } // n 被優化至寄存器 SI,a 在數據段固定位置

編譯器將 n=2; n++ 合併為 mov si, 3,n 全程駐留寄存器,不佔棧空間。啟示:Debug 模式下變量才嚴格按語義存儲;Release 優化會打破「局部變量必在棧」的假設。

程序三:數據類型大小、對齊與運算指令差異

int a; char b; long c; // 地址連續:a(2B), b(1B), c(4B) -> 差值 2,1,2
a++; b++; c++;
  • int/char:inc word ptr [bp-x] / inc byte ptr [bp-y]
  • long:add word ptr [bp-z], 1 + adc word ptr [bp-z+2], 0 (模擬 32 位加法)

TC 2.0 類型大小:char=1, int=2, long=4, float=4, double=8。結構體成員按聲明順序連續排列,無填充 (16位模式下)。

程序四:結構體變量在數據段 vs 棧段

struct stu { int id; char name[3]; } a; // 全局 -> DS
void f() { struct stu b; } // 局部 -> SS, 入口 sub sp, 5 分配

全局結構體在 DS 連續佔 5 字節;局部結構體在棧幀中連續佔 5 字節,用 mov 而非 push 初始化。

程序五:結構體作為參數與返回值

struct stu func(struct stu s) { return s; }
  • 傳參:調用者將結構體逐字節壓棧 (5 字節),被調用者在棧中訪問副本。
  • 返回:被調用者在數據段分配靜態臨時結構體,將返回值拷貝進去,返回其 偏移地址 (AX)。調用者再從該地址拷貝到目標。
    原因:AX 只有 16 位,裝不下 5 字節結構體。

總結與現代視角

16 位實模式下的段:偏移寻址、調用者清棧 CDECL、結構體返回值通過靜態臨時區地址傳遞,是 x86 早期 ABI 的縮影。現代 x86-64 System V ABI:
- 參數前 6 個用寄存器 (RDI, RSI, RDX, RCX, R8, R9),其餘上棧。
- 返回值:整數/指針用 RAX,浮點用 XMM0,大結構體由調用者分配空間並傳遞隱藏指針 (RDI)。
- 紅區、影子空間、栈對齊 16B 等新規則。
理解底層機制,才能寫出高性能、可移植的系統代碼,也能看懂編譯器優化後的汇編輸出。

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