前言

众所周知c语言不支持重载,虽然重载给编写代码还是带来了不少的便利性。如果想要在c语言中实现重载,那就需要一些特殊的手段了,比如说使用宏。本文讲述的方法是,网上已经存在,笔者经过实践调整实现以兼容不同编译器。


一、如何实现?

基本原理是通过宏的参数的个数,定位到对应参数个数的函数,所以只能通过参数个数区分重载

1、基础宏

#if defined(_MSC_VER)
#define _AC_OVERLOAD_T(t) t
#define _AC_OVERLOAD_N(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, N, ...) N
#define AC_OVERLOAD(...) _AC_OVERLOAD_T(_AC_OVERLOAD_N(__VA_ARGS__))
#else
#define _AC_OVERLOAD_T(...) _AC_OVERLOAD_N(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _AC_OVERLOAD_N(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, N, ...) N 
#define _AC_CAT(a, b) a##b
#define AC_CAT(a, b) _AC_CAT(a, b)
#define _AC_OVERLOAD(func, N) AC_CAT(func##_, N)
#define AC_OVERLOAD(func, ...) _AC_OVERLOAD(func, _AC_OVERLOAD_T(__VA_ARGS__))(__VA_ARGS__)
#endif

2、定义函数

//规则是名称+_数字(参数个数)
// 函数一
void add_1(int a)
{
	printf("call add1 \n");
}
// 函数二
void add_2(int *array, int len)
{
	printf("call add2 \n");
}

3、定义重载宏

当前版本,CL和其他编译器不同,所以需要定义两套重载宏函数。

#if defined(_MSC_VER)
// CL相对麻烦一些,需要在AC_OVERLOAD相应位置替换为对应参数个数的函数
#define add(...) AC_OVERLOAD(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, add_2(__VA_ARGS__), add_1(__VA_ARGS__), 0)
#else
// gcc的较清晰明了:拼接规则是函数名称+_数字(参数个数)。
// add(...) 为调用的名称可以自定义。AC_OVERLOAD中的add为上面定义的函数不带_数字的部分。
#define add(...) AC_OVERLOAD(add, __VA_ARGS__)
#endif

4、调用

add(1);
int array[]={0,1};
add(array,2);

二、完整示例

代码如下(示例):

#include <stdio.h>
//基础宏 通用的
#if defined(_MSC_VER)
#define _AC_OVERLOAD_T(t) t
#define _AC_OVERLOAD_N(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, N, ...) N
#define AC_OVERLOAD(...) _AC_OVERLOAD_T(_AC_OVERLOAD_N(__VA_ARGS__))
#else
#define _AC_OVERLOAD_T(...) _AC_OVERLOAD_N(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _AC_OVERLOAD_N(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, N, ...) N 
#define _AC_CAT(a, b) a##b
#define AC_CAT(a, b) _AC_CAT(a, b)
#define _AC_OVERLOAD(func, N) AC_CAT(func##_, N)
#define AC_OVERLOAD(func, ...) _AC_OVERLOAD(func, _AC_OVERLOAD_T(__VA_ARGS__))(__VA_ARGS__)
#endif

//当前需要重载方法的宏
#if defined(_MSC_VER)
// CL相对麻烦一些,需要在AC_OVERLOAD相应位置替换为宏
#define add(...) AC_OVERLOAD(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, add_2(__VA_ARGS__), add_1(__VA_ARGS__), 0)
#else
// gcc的较清晰明了:拼接规则是函数名称+_数字(参数个数)。
// add(...) 为调用的名称可以自定义。AC_OVERLOAD中的add为上面定义的函数不带_数字的部分。
#define add(...) AC_OVERLOAD(add, __VA_ARGS__)
#endif

//具体重载的函数,规则是名称+_数字(参数个数)
// 函数一
void add_1(int a)
{
	printf("call add1 \n");
}
// 函数二
void add_2(int *array, int len)
{
	printf("call add2 \n");
}

//调用
int main()
{
	add(1);
	int array[] = {0, 1};
	add(array, 2);
	return 0;
}

效果预览:
在这里插入图片描述


总结

以上就是今天要讲的内容,当前的实现不同编译器略有差异,所以使用起来略微麻烦一些,但是总的来说也是稳定实现了简单的函数重载,具有一定的实用性,后面可能会研究下CL的宏能否进一步优化。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐