許多開發者初學 C 語言時著重語法與 API,卻忽略了它貼近硬體的本質。本系列文章將從組合語言、CPU 架構、記憶體模型等底層視角,重新審視 C 語言的核心機制,目標是:「看到 C 代碼,腦海中浮現對應的組合指令與記憶體佈局」。
K&R 指出 int 「反映宿主機器整數的自然大小」。這句話背後藏著什麼硬體真相?
int 大小?/* 查看目前平台型態大小 */
printf("char=%zu short=%zu int=%zu long=%zu long long=%zu\n",
sizeof(char), sizeof(short), sizeof(int),
sizeof(long), sizeof(long long));
/* 32-bit Linux 典型輸出:1 2 4 4 8 */
/* 64-bit Linux 典型輸出:1 2 4 8 8 */
編譯器依據 ABI (Application Binary Interface) 文件(如 System V AMD64 ABI)決定各型態大小與對齊需求,核心考量:
int 通常等於暫存器寬度,便於單指令運算。long 可能維持 32 bits (Windows x64) 或擴為 64 bits (Linux x64)。早期 C 設計假設「指標可存入 int」,雖 C99 引入 intptr_t/uintptr_t 修正,但字長統一簡化了:
/* test_add.c */
int main(void) {
int a = 1, b = 2;
int c = a + b;
return 0;
}
$ gcc -Og -S test_add.c -o test_add.s
$ cat test_add.s
main:
pushq %rbp
movq %rsp, %rbp ; 建立堆疊幀
movl $1, -4(%rbp) ; a = 1
movl $2, -8(%rbp) ; b = 2
movl -8(%rbp), %edx ; 載入 b
movl -4(%rbp), %eax ; 載入 a
addl %edx, %eax ; a + b → %eax
movl %eax, -12(%rbp) ; 存回 c
popq %rbp
ret
觀察重點:
rbp 正負位移)eax/edx) 完成addl 為 32 位元加法,對應 int下一篇將深入資料編碼:
#pragma pack / __attribute__((packed)) 實戰C 語言不是「高階組合語言」,而是可移植的組合語言。理解編譯器如何將抽象語法映射到具體指令與記憶體,才能寫出高效、正確、可移植的系統級代碼。讓我們一起拆解黑盒,直抵機器本質。