当前位置: 首页 > 科技观察

原来C语言也可以这样实现“泛型编程”!

时间:2023-03-14 11:29:39 科技观察

本文转载自微信公众号《编程珠玑》,作者守望老师。转载本文请联系编程诸暨公众号。在回答标题问题之前,我们先了解一下什么是泛型编程。通用编程是编程语言的一种风格或范例。泛型允许程序员在用强类型编程语言编写代码时使用一些后面指定的类型,并在实例化时将这些类型指定为参数。C++支持泛型编程,即模板,例如://来源:公众号【编程珠玑】//作者:守望先生#includetemplateTadd(Ta,Tb){Tret=a+b;std::cout<//Int类型加法intaddI(inta,intb){printf("%d+%d=%d\n",a,b,a+b);return(a+b);}//double类型加法doubleaddF(doublea,doubleb){printf("%f+%f=%f\n",a,b,a+b);return(a+b);}voidunsupport(inta,intb){printf("unsupporttype\n");}#defineADD(a,b)_Generic((a),\int:addI(a,b),\double:addF(a,b),\default:unsupport(a,b))intmain(void){ADD(1,2);ADD(1.1,2.2);return0;}观察上面的代码,我们注意到:这里,我们需要定义两种加法(实际上,编译器是通过C++模板为我们做的),因为在C语言中不支持重载,所以两次添加的函数名称不同。由于涉及到两个参数,在进行类型判断时,如果两个参数不一致,仍然可能会出现编译问题。调用者不需要区分添加对象的类型,可以使用ADDC99的tgmath.h。前面说了_Generic关键字只有C11才有,那么C99呢?事实上,tgmath.h提供了一些泛型类型的宏。如果在math.h的函数中定义了float、double和longdouble版本,tgmath将提供一个Generic类型的宏。效果同上例,例如://来源:公众号【编程珠玑】//作者:守望先生#include#includeintmain(void){floatf=4.0f;longdoubled=1.44;printf("%f\n",sqrt(f));//实际调用了sqrtfprintf("%Lf\n",sqrt(d));//实际调用了sqrtlreturn0;}编译运行结果:2.0000001.200000但是不得不说的是tgmath中提供的泛型宏也是有限的。众所周知,C语言中的void*指针是一种无类型指针。从这个角度来看,它也可以看作是一个泛型指针。并且它的使用在C语言中非常普遍。比如在《高级指针话题-函数指针》中,我们介绍了快速排序接口的使用,其函数声明如下:#includevoidqsort(void*base,size_tnmemb,size_tsize,int(*compar)(constvoid*,常量*));库函数qsort实际上是一种通用的排序算法,可以对任意类型的数据进行排序。当然有个前提,你需要根据它的协议实现一个比较函数来比较大小。类似这样的例子在C语言中还有很多,但是相对于其他语言,比如C++中的模板,这种所谓的泛型确实有点小巫见大巫。总结C语言语法本身基本上不支持泛型编程,但是借助_Generic关键字和一些手段,可以实现泛型编程。作者:守望,linux应用开发者,目前在公众号【编程明珠】?上分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源。