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

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

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

#include 
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 
#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 
// 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 
#include 
int main(void)
{float f = 4.0f;long double d = 1.44;printf("%f\n",sqrt(f)); // 实际上调用了sqrtfprintf("%Lf\n",sqrt(d)); // 实际上调用了sqrtlreturn 0;
}

编译运行结果:

2.000000
1.200000

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

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338633.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javadoc 标签_新的Javadoc标签@ apiNote,@ implSpec和@implNote

javadoc 标签如果您已经在使用Java 8&#xff0c;则可能会看到一些新的Javadoc标签&#xff1a; apiNote &#xff0c; implSpec和implNote 。 他们怎么了&#xff1f; 如果要使用它们&#xff0c;该怎么办&#xff1f; 总览 该帖子将快速查看标签的来源和当前状态。 然后&…

c语言万年历附加功能,万年历(c语言,多功能).doc

万年历(c语言,多功能)#include "time.h" /*包含的头文件*/#include "stdio.h"#include "math.h"#include "windows.h"#include "conio.h"#define KEYNUMUp 0x48 /*宏定义*/#define KEYNUMDown 0x50#define KEYNUMLeft 0x4b#…

联想小新300加固态_就联想小新 Pro 13 固态硬盘混用一事,官方回应

IT之家11月3日消息 近日有用户反馈称&#xff0c;联想小新Pro 13的部分批次固态硬盘从三星PM981A换成亿联了&#xff0c;因此还出现了退货现象。针对上述情况&#xff0c;联想官方刚刚发表声明回应此事。以下为联想回应全文&#xff1a;有关小新Pro 13固态硬盘(SSD)配置问题的公…

C语言入门基础之输入和输出

标准输入函数在stdio.h中scanf声明如下&#xff1a;/* Read formatted input from stdin.This function is a possible cancellation point and therefore notmarked with __THROW. */ extern int scanf (const char *__restrict __format, ...) __wur;使用Mac或Linux的同学&am…

camel java_与Java EE和Camel的轻量级集成

camel javaEnterprise Java具有不同的风格和观点。 从简单的平台技术&#xff08;众所周知的Java EE&#xff09;开始&#xff0c;到不同的框架和集成方面&#xff0c;最后是涉及以数据为中心的用户界面或特定可视化效果的用例。 Java EE本身无法解决的最突出的问题是“集成”。…

c语言 伪随机数程序,C语言的伪随机数

一直想好好的系统的学习一下C语言的伪随机数&#xff0c;今天终于逮到机会了伪随机数C语言中有可以产生随机数据的函数&#xff0c;需要添加stdlib.h和time.h头文件。首先在main函数开头加上srand(unsigned)time(NULL))。先来介绍一下srand头文件&#xff1a;定义函数&#xff…

最大隶属度原则_模糊数学笔记:六、模糊模型识别-I(最大隶属度原则)

1、模型识别的问题提出模型识别&#xff0c;通俗地理解即是对一个类别未知的对象进行归类&#xff08;或者叫分类&#xff09;。这里与聚类不同的是&#xff0c;聚类实际上是要区分出已有的样本哪些属于同一类&#xff0c;但并没有参考标准。而识别则事先有参考的标准&#xff…

C语言经典题

C 库函数 - tanh()描述C 库函数 double tanh(double x) 返回 x 的双曲正切。声明下面是 tanh() 函数的声明。double tanh(double x)参数x -- 浮点值。返回值该函数返回 x 的双曲正切。实例下面的实例演示了 tanh() 函数的用法。#include#include int main (){ double x, ret;…

用c语言产生大素数,C语言实现寻找大素数

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼找到一亿内所有素数并写入文件用时 35秒.#include "math.h"#include "stdio.h" #include "stdlib.h" #include "time.h"int isP(int num,int *p) { int i; int lenp[0]; int flag1; p;for…

java ee自动生成编码_EE Servlet 3:在Servlet中生成HTML输出

java ee自动生成编码如果您只需要在EE Web模块中处理少量请求URI&#xff0c;那么在Servlet代码中生成自己HTML响应可能比使用完整的模板库更容易。 作为示例的一部分&#xff0c;我尝试了一个非常简单的Java DSL&#xff0c;该Java DSL在编写自己的Serlvet时生成html输出。 代…

jq 控制td只显示一行_CSS让表格里的内容强制显示一行,超出长度显示省略号

在写html页面的时候&#xff0c;会经常用到表格&#xff0c;而且很多时候一个tr里边需要包含好几个td&#xff0c;这样就会导致tr的高度不一致&#xff0c;被撑开了这时候&#xff0c;如果能让td里的内容强制显示在一行&#xff0c;并让超出边界范围的内容显示点点&#xff0c;…

C++11的模板改进

C11关于模板有一些细节的改进&#xff1a;模板的右尖括号模板的别名函数模板的默认模板参数模板的右尖括号C11之前是不允许两个右尖括号出现的&#xff0c;会被认为是右移操作符&#xff0c;所以需要中间加个空格进行分割&#xff0c;避免发生编译错误。int main() {std::vecto…

java面试题2014_Java生态系统– 2014年我的5大亮点

java面试题20141月1日-RedMonk Analyst公司宣布Java比以往任何时候都更加流行和多样化&#xff01; 2014年&#xff0c;随着FOSDEM的Free Java会议室的年会&#xff0c;Java生态系统开始轰轰烈烈地响起。 除了关于OpenJDK和相关主题的许多精深的技术讲座外&#xff0c;Steve OG…

android 第三方圆弧进度条,android 可配置的圆弧进度条

Arc ProgressBar Configurable 圆弧环形进度条DEMOAttributesnameformatdescriptionborderWidthinteger圆弧边框的宽度progressStyletick/arc进度条类型&#xff0c;tick 为带刻度的radiusinteger半径arcbgColorcolor圆弧的边框背景degreeinteger弧度&#xff0c;设置为 0 即为…

三分钟让孩子的数学开窍

周末给孩子灌了一个世界观和方法论&#xff1a;用笛卡尔坐标系描述世界。 我强调&#xff0c;学习笛卡尔坐标系不是做题&#xff0c;它是工具&#xff0c;它是帮你解题的&#xff0c;而不是为难你的。 任何数学题放在笛卡尔坐标系都可以通过机械的方法硬算&#xff0c;计算过程…

oracle大对象实例_超大型Oracle数据库设计实例

超大型系统的特点为&#xff1a; 1.处理的用户数一般都超过百万&#xff0c;有的还超过千万&#xff0c;数据库的数据量一般超过1TB&#xff1b; 2.系统必须提供实时响应功能&#xff0c;系统需不停机运行&#xff0c;要求系统有很高的可用性及可扩展性。 这篇是笔者针对以上特…

C++定时器的实现之格式修订版

个人认为一个完备的定时器需要有如下功能&#xff1a;在某一时间点执行某一任务在某段时间后执行某一任务重复执行某一任务N次&#xff0c;任务间隔时间T那么如何实现定时器呢&#xff1f;下面是我自己实现的定时器逻辑&#xff0c;源码链接最后会附上。定时器中主要的数据结构…

java 性能调优_Java性能调优调查结果(第四部分)

java 性能调优这是本系列中的最后一篇文章&#xff0c;我们将分析我们在2014年10月进行的Java Performance Tuning Survey的结果。如果您尚未阅读第一篇文章&#xff0c;建议您首先阅读以下内容&#xff1a; 性能问题的频率和严重性 最受欢迎的监控解决方案 查找根本原因的工…

Android接入热敏打印机,Android 关于佳博和汉印蓝牙热敏打印机开发

接上篇文章Android之BLE(低功耗)蓝牙开发&#xff0c;本篇文章针对上篇博文中提出的两款打印机的开发流程进行记录。首先不管时佳博打印机还是汉印打印机&#xff0c;都是先对他们各自的lib进行导入&#xff0c;如图&#xff1a;导入lib之后&#xff0c;一定要记得进行sync pro…

C 桥接模式 - 开关和电器

桥接模式&#xff08;Bridge Pattern&#xff09;是将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。1模式结构UML 结构图&#xff1a;Abstraction&#xff08;抽象类&#xff09;&#xff1a;用于定义抽象类的接口&#xff0c;并且维护一个指向 Implementor…