現象
int func() { return 0; }
printf("%zu\n", sizeof(func)); // 輸出 1 (GCC/Clang) 或編譯錯誤 (MSVC)
為什麼 sizeof(func) 結果是 1?為什麼不報錯?
標準規定 (C99/C11/C17)
C 標準 6.5.3.4/1:
sizeof 運算元可以是類型名稱或運算式。若為運算式,**不求值**,只根據運算式的類型推導大小。
函數名在運算式中的類型
- 函數名
func 在大多數上下文會隱式轉換為 **函數指標** int (*)()
- 但
sizeof、_Alignof、& (取址) 是**例外**,函數名保持 **函數類型** int ()
為什麼是 1?GCC 的歷史兼容性擴展
GCC 文檔明確說明:
對於 sizeof(函數類型),GCC 定義其大小為 1,以便於指標運算兼容性(早期代碼可能做 ptr + sizeof(func) 類似操作)。這是 GNU 擴展,**非標準行為**。
各編譯器行為對比
| 編譯器 | sizeof(func) | sizeof(&func) | 標準合規性 |
| GCC / Clang | 1 (警告: "sizeof on function type returns 1") | 指標大小 (4/8) | GNU 擴展,非標準 |
| MSVC | 編譯錯誤 C2070: "illegal sizeof operand" | 指標大小 | 嚴格遵循標準 |
| 標準 C | **約束違規**,必須診斷 | 指標大小 | 函數類型不完整,不可用 sizeof |
標準視角的「為什麼」
C 標準規定:不完整類型不可作為 sizeof 運算元。函數類型 int () 屬於不完整類型(無長度、無佈局),因此標準合規編譯器**必須報錯**。GCC 為了兼容舊代碼,選擇給出 1 並警告,而非硬性報錯。
正確做法
- 想要函數指標大小:
sizeof(&func) 或 sizeof(int(*)())
- 想要函數機器碼大小:**C 標準無法獲取**,需平台特定手段(如
objdump、鏈接器映射文件)
- 編寫可移植代碼:永遠不要對函數名直接使用 sizeof
相關陷阱:數組參數退化
void foo(int arr[100]) {
printf("%zu\n", sizeof(arr)); // 輸出指標大小 (4/8),非 400!
// 參數實際為 int *arr,數組信息丟失
}
總結
sizeof(func) == 1 是 **GCC 的非標準擴展**,為歷史兼容性而存在。標準 C 規定函數類型不完整,不可用 sizeof,合規編譯器會報錯。編寫可移植代碼時,**避免對函數名使用 sizeof**,改用 sizeof(&func) 獲取指標大小,或查閱平台文檔獲取機器碼大小。
- 上一篇文章: Windows 桌面開發:控制繪圖刷新間隔的正確姿勢(Sleep + 消息泵)
- 下一篇文章: 數值分析編程入門:從題目理解到代碼實現的完整思路指導
Copyright ©
程式碼之家 All Rights Reserved