# C 语言重载
很多时候我在思考 C 语言 和 CPP 一样允许函数重载,调用函数会方便很多.
我去翻了很多 源码 和 文档,算是找到了一些 类似的方法.
由于 C 语言 的底层 实现与 CPP 不同,所以不可能实现百分百的重载.
C 语言的 POSIX 标准 的 open()
函数就实现了重载,大概率是这样的实现的 —— 依赖函数参数
# 方法一:
运用函数指针,指向函数实体, 而 函数名 由宏定义实现,例子如下
typedef struct CC{ | |
int a; | |
int b; | |
}CC; | |
void func_int(void *a) | |
{ | |
printf("%d\n",*(int*)a); | |
} | |
void func_double(void *a) | |
{ | |
printf("%d\n",*(int*)a); | |
} | |
void func_int(void *a) | |
{ | |
printf("%d\t",((CC*)a)->a); | |
printf("%d\n",((CC*)a)->b); | |
} | |
typedef void (*ptr)(void *); | |
void c_func(ptr fun_ptr, void *param) | |
{ | |
fun_ptr(param); // 调用对应函数 | |
} | |
int main() | |
{ | |
int a = 23; | |
double b = 23.23; | |
CC CA = {10, 11}; | |
c_func(func_int, &a); // 整数 | |
c_func(func_double, &b); // 浮点 | |
c_func(func_struct, &CA); // 结构体 | |
return 0; | |
} |
优点是 实现起来很简单,不需要外加头文件
这个方法的问题很明显,我们仍然需要记住相关函数的名称,而且函数的参数个数也受到相应的限制
# 方法二:
使用可变参数类型 `va_list` 来获取 从(...) 输入的所有参数, 通过第二个参数来决定使用哪一个函数
例子如下:
void va_overload2(int p1, int p2) | |
{ | |
printf("va_overload2 %d %d\n", p1, p2); | |
} | |
void va_overload3(int p1, int p2, int p3) | |
{ | |
printf("va_overload3 %d %d %d\n", p1, p2, p3); | |
} | |
void va_overload4(int p1, int p2, int p3, int p4) | |
{ | |
printf("va_overload4 %d %d %d %d\n", p1, p2, p3, p4); | |
} | |
static void va_overload(int p1, int p2, ...) | |
{ | |
switch (p2) | |
{ | |
case 2: | |
{ | |
va_list v; | |
va_start(v, p2); | |
int p3 = va_arg(v, int); | |
va_end(v); | |
va_overload3(p1, p2, p3); | |
break; | |
} | |
case 3: | |
{ | |
va_list v; | |
va_start(v, p2); | |
int p3 = va_arg(v, int); | |
int p4 = va_arg(v, int); | |
va_end(v); | |
va_overload4(p1, p2, p3, p4); | |
break; | |
} | |
default: | |
{ | |
va_overload2(p1, p2); | |
break; | |
} | |
} | |
} |
# 方法三
前面三种,说是重载其实更像是一般的条件语句. 下面这种就略微像 CPP 的函数重载
模拟了 CPP 重载函数 底层编译过程, 对函数进行重命名
// 粘合宏,用于 函数粘合函数名称 | |
#define CAT(A, B) CAT2(A, B) | |
#define CAT2(A, B) A##B | |
#define c_overload(...) \ | |
CAT(overload, COUNT_PARMS(__VA_ARGS__)) \ | |
(__VA_ARGS__) | |
#define COUNT_PARMS(...) \ | |
COUNT_PARMS2(0, ##__VA_ARGS__, PARMS_N_RESQ()) | |
#define COUNT_PARMS2(...) \ | |
COUNT_PARM3(__VA_ARGS__) | |
// 最大 参数列表,可调 目前为 (0 ~ 63) | |
#define COUNT_PARM3( \ | |
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ | |
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ | |
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ | |
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ | |
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ | |
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ | |
_61, _62, _63, N, ...) N | |
#define PARMS_N_RESQ() \ | |
63, 62, 61, 60, \ | |
59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ | |
49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ | |
39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ | |
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ | |
19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ | |
9, 8, 7, 6, 5, 4, 3, 2, 1, 0 | |
void overload1(int p1) | |
{ | |
printf("CPP One param: %d\n", p1); | |
} | |
void overload2(double *p1, const char *p2) | |
{ | |
printf("CPP Two params: %p (%f) %s\n", p1, *p1, p2); | |
} | |
void overload3(int p1, int p2, int p3) | |
{ | |
printf("CPP Three params: %d %d %d\n", p1, p2, p3); | |
} |
方法三 通过 COUNT_PARMS 来 数出参数个数,然后使用 ## 来 将 overload 和 得到的参数个数粘合.
得到函数名 overloadx
, 从而实现 "重载"