C++ 通過 Name Mangling(名字修飾)原生支持函數重載,編譯器會根據參數類型將同名函數重命名為 _Z4funcv、_Z4funci、_Z4funcif 等內部符號。C 標準不提供此機制,但在系統編程、API 設計中,同名不同參數的接口極大提升易用性——POSIX open() 就是典型例子:open(path, flags) 與 open(path, flags, mode) 共存。
利用 <stdarg.h> 的 va_list 機制,通過約定俗成的參數標識(如參數個數、首參數值)判斷實際調用哪個內部函數:
static void va_overload(int p1, int p2, ...) {
if (p2 == 3) {
va_list v; va_start(v, p2);
int p3 = va_arg(v, int); va_end(v);
va_overload3(p1, p2, p3); return;
}
va_overload2(p1, p2);
}
缺點:類型安全全靠程序員自覺,易出錯;參數檢查在運行期。
__builtin_types_compatible_p編譯期根據實參類型選擇分支,零運行時開銷:
#define gcc_overload(A) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(A), struct s1), \
gcc_overload_s1(*(struct s1 *)&A), \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(A), struct s2), \
gcc_overload_s2(*(struct s2 *)&A), (void)0))
進階寫法結合 switch 與可變參數,可擴展支持任意類型組合。
利用 _Generic(C11)或宏拼接生成不同函數名,本質上是編譯期重命名,非真正重載。
C 實現重載需編寫大量樣板代碼,門檻較高。除非 API 設計強制要求,否則優先考慮不同函數名(如 foo_int()、foo_str())或結構體參數封裝,代碼更清晰、可維護性更強。