C语言/C++学习之C语言实现“泛型编程”
小职 2020-12-29 来源 :「编程珠玑」,作者守望先生 阅读 917 评论 0

摘要:本文主要向大家介绍了C语言/C++学习之C语言实现“泛型编程” ,通过具体的内容向大家展现,希望对大家学习C语言/C++有所帮助。

本文主要向大家介绍了C语言/C++学习之C语言实现“泛型编程” ,通过具体的内容向大家展现,希望对大家学习C语言/C++有所帮助。

C语言/C++学习之C语言实现“泛型编程”


在回答标题问题之前,先了解下什么是泛型编程。

 

泛型编程(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。C++支持泛型编程,也就是模板,比如:

 


#include <iostream>

template <class T>

T add(T a,T b){

  T ret = a + b;

  std::cout<< a << " + " << b <<" = " << ret << std::endl;

  return ret;

}

int main(){

  add(1,2);  // 整数相加

  add(1.2,2.3); // 浮点数相加

  return 0;

}

运行结果:

 

1 + 2 = 3

1.2 + 2.3 = 3.5

从上面的结果可以看到,对于调用add函数,如果传入的是整型,则按照整型加法计算,如果是浮点数,则按照浮点数进行加法计算。也就是说,add函数没有针对特定类型(泛型)。

 

你同样可以使用重载实现上面的功能,但是存在大量重复代码。

 

C语言支持泛型编程吗?

 

很遗憾,C语言本身不支持真正意义上的泛型编程,但是却在一定程度上可以“实现泛型编程”。

 

_Generic关键字

 

_Generic是C11的关键字,通过该关键字可以有一个泛型表达式:

 

_Generic((value). int:"int", float:"float",char*:"char*",default:"other type")

什么意思呢?如果value是int类型,那么表达式的值就是“int”,其他的以此类推。看起来是不是和switch语句有点类似呢?

 

根据这个示例,我们来实现一个功能,打印变量或常量到底是什么类型:

 


#include <stdio.h>

#define TYPE(v) _Generic((v), \

    int:"int", \

    char:"char", \

    float:"float", \

    double:"double", \

    char*:"char*", \

    default:"other type")

int main(void)

{

    printf("1 + 2 type: %s\n",TYPE(1 + 2));

    printf("1/3 type: %s\n",TYPE(1/3));

    printf("2/3 type: %s\n",TYPE((float)2/3));

    printf("xxx type: %s\n",TYPE("xxx"));

    return 0;

}

这里为了方便使用,我们通过define关键字,将泛型表达式简化。

 

运行结果:

 

1 + 2 type: int

1/3 type: int

2/3 type: float                                                         

xxx type: char*

可以看到通过TYPE就可以获得表达式的结果类型,这对初学者来说,可真是福音了。

 

泛型算法

 

既然C语言有_Generic关键字了,那么我们尝试实现开头C++示例代码中的加法。看过上面的例子后,相信你已经会了:

 

#include <stdio.h>

// int类型加法

int addI(int a, int b)

{

    printf("%d + %d = %d\n",a,b, a + b );

    return (a + b);

}

// double类型加法

double addF(double a, double b)

{

    printf("%f + %f = %f\n",a,b, a + b );

    return (a + b);

}

void unsupport(int a,int b)

{

    printf("unsupport type\n");

}

#define ADD(a,b) _Generic((a), \

    int:addI(a,b),\

    double:addF(a,b), \

    default:unsupport(a,b))

int main(void)

{

    ADD(1 , 2);

    ADD(1.1,2.2);

    return 0;

}

观察上面的代码,我们注意到:

 

在这里,我们需要定义两种类型的加法(实际上,通过C++的模板,由编译器帮我们完成了这件事),由于C语言中并不支持重载,因此两个加法的函数名不一样。

由于涉及参数有两个,在做类型判断时,如果两个参数不一致,可能仍然存在编译问题

调用者无需区分被加对象是什么类型,都可以统一使用ADD

C99的tgmath.h

 

前面说到,_Generic关键字在C11中才有,那么C99怎么办呢?实际上,tgmath.h中提供了一些泛型类型宏,如果math.h的函数中定义了float,double和long double版本,tgmath就会提供一个泛型类型宏。效果和前面的例子一样,举个例子:

 


#include <stdio.h>

#include <tgmath.h>

int main(void)

{

    float f = 4.0f;

    long double d = 1.44;

    printf("%f\n",sqrt(f)); // 实际上调用了sqrtf

    printf("%Lf\n",sqrt(d)); // 实际上调用了sqrtl

    return 0;

}

编译运行结果:

 

2.000000

1.200000

但是不得不说,tgmath中提供的泛型宏也是有限的。

 

void *指针

 

众所周知,C语言中void *指针是一种无类型指针,从这点看,也可以算是泛型指针了。而它的使用在C语言中是非常常见的,举例来说,在《高级指针话题-函数指针》中,我们介绍了快速排序接口的使用,它的函数声明是这样的:

 

#include <stdlib.h>

void qsort(void *base, size_t nmemb, size_t size,

                  int (*compar)(const void *, const void *));

库函数qsort实际上就是泛型排序算法了,它可以针对任何类型的数据进行排序。当然有一个前提,就是你需要按照它的协议,实现一个compar函数,用于比较大小。

 

像这样类似的例子,C语言中还有很多,不过相比于其他语言,如C++中的模板,这种所谓的泛型,确实有些小巫见大巫了。

 

总结

 

C语言语法上本身基本不支持泛型编程,但是借助_Generic关键字和一些手段,可以实现泛型编程。



关注“职坐标在线”(Zhizuobiao_Online)公众号,免费获取学习视频资料、技术就业咨询

C语言/C++学习之C语言实现“泛型编程”

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程