void func(int x, int y, int z) {
printf("x = %d at [%p]\n", x, &x);
printf("y = %d at [%p]\n", y, &y);
printf("z = %d at [%p]\n", z, &z);
}
int main() { func(100, 200, 300); }
輸出 (x86, 棧高→低):
x = 100 at [00BFE28760] // 高地址
y = 200 at [00BFE28764]
z = 300 at [00BFE28768] // 低地址 (棧頂)
地址遞增說明:參數 z 最後入棧,位於棧頂 (低地址);x 最先入棧,位於棧底 (高地址)。即 從右向左 (Right-to-Left) 入棧。
這是 C 語言區別於 Pascal (左→右) 的關鍵設計決策。
| 入棧順序 | 棧佈局 (高地址→低地址) | 首參數位置 | 可變參可行性 |
|---|---|---|---|
| 左→右 (Pascal) | [Arg1][Arg2][Arg3...][RetAddr][OldEBP] | 棧底 (最深處) | ❌ 無法定位首參數 (除非知參數總數) |
| 右→左 (C) | [ArgN...][Arg2][Arg1][RetAddr][OldEBP] | EBP+8 (固定偏移) | ✅ 首參數地址固定,後續參數可通過格式化字符串推導 |
printf("format", ...) 等可變參函數。format) 是**第一個參數**,必須在固定、可計算的位置被找到。format 在棧底,被後續不定數量參數「蓋住」,無法直接定位。format 最後入棧,位於 **EBP+8** (假設標準幂框架),地址固定不變。format 確定後續參數個數/類型,再按順序向高地址偏移訪問。__cdecl (右→左, 調用者清理)、__stdcall (右→左, 被調用者清理)、__fastcall (前兩參寄存器) 等,均保持右→左語義以兼容可變參邏輯。C 語言參數從右向左入棧,本質是為了**在棧上為首參數預留固定地址**,從而實現可變參數這一核心特性。這是 C 語言在系統編程領域靈活性與效率平衡的經典設計證明。