C 基础 _Generic 泛型应用
引言 - _Generic 用法简介
#include <stdio.h> #define TYPENAME_CASE(type) \
type: #type, #define TYPENAME_POINTER_CASE(type) \
TYPENAME_CASE(type) \
TYPENAME_CASE(type *) \ #define TYPENAME_UNSIGNED_CASE(type) \
TYPENAME_POINTER_CASE(type) \
TYPENAME_POINTER_CASE(unsigned type) \ #define TYPENAME(x) _Generic((x), \
TYPENAME_POINTER_CASE(_Bool) \
TYPENAME_UNSIGNED_CASE(char) \
TYPENAME_UNSIGNED_CASE(short) \
TYPENAME_UNSIGNED_CASE(long) \
TYPENAME_UNSIGNED_CASE(long long) \
TYPENAME_POINTER_CASE(float) \
TYPENAME_POINTER_CASE(double) \
TYPENAME_POINTER_CASE(long double) \
TYPENAME_POINTER_CASE(float _Complex) \
TYPENAME_POINTER_CASE(double _Complex) \
TYPENAME_CASE(void *) \
default: "other" \
) int main(int argc, char * argv[]) {
double _Complex c;
double _Complex * p = &c; puts(TYPENAME(p)); return ;
}
{ warning 点睛呀, GCC 亲自指出自己的 BUG}
正文 - _Generic 实现函数重载
#include <stdio.h> void foo_void(void) {
printf("void\n");
} void foo_int(int c) {
printf("int: %d\n", c);
} void foo_char(char c) {
printf("char: %c\n", c);
} void foo_double(double c) {
printf("double: %f\n", c);
} void foo_double_int(double c, int d) {
printf("double: %f, int: %d\n", c, d);
} #define foo(...) \
SELECT(__VA_ARGS__)(__VA_ARGS__) #define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y #define SELECT(...) \
CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__) #define SELECT_0() \
foo_void #define SELECT_1(_1) _Generic((_1), \
int: foo_int, \
char: foo_char, \
double: foo_double \
) #define SELECT_2(_1, _2) _Generic((_1), \
double: _Generic((_2), \
int: foo_double_int \
) \
) #define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, /*...*/ N, ...) N #define NARG(...) \
ARGN(__VA_ARGS__ COMMA(__VA_ARGS__) , , , )
#define HAS_COMMA(...) \
ARGN(__VA_ARGS__, , , ) #define SET_COMMA(...) , #define COMMA(...) SELECT_COMMA( \
HAS_COMMA(__VA_ARGS__), \
HAS_COMMA(__VA_ARGS__ ()), \
HAS_COMMA(SET_COMMA __VA_ARGS__), \
HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
) #define SELECT_COMMA(_0, _1, _2, _3) \
SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) \
COMMA_ ## _0 ## _1 ## _2 ## _3 #define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
#define COMMA_0011 ,
#define COMMA_0100 ,
#define COMMA_0101 ,
#define COMMA_0110 ,
#define COMMA_0111 ,
#define COMMA_1000 ,
#define COMMA_1001 ,
#define COMMA_1010 ,
#define COMMA_1011 ,
#define COMMA_1100 ,
#define COMMA_1101 ,
#define COMMA_1110 ,
#define COMMA_1111 , int main(int argc, char** argv)
{
foo();
foo();
foo(10.12);
foo(12.10, );
foo((char)'s'); return ;
}
{
代码脉络可以详细参照下面 1和 2 讨论. 思索大师的思维 ~
1. https://stackoverflow.com/questions/479207/how-to-achieve-function-overloading-in-c?rq=1
2. https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
}
对于上面 put.c 演示的 COMMA 宏, 我们用下面一段 demo (define.c)来简单拆解其中一部分思路
#include <stdio.h> // https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ #define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) //
// _TRIGGER_PARENTHESIS_ __VA_ARGS__ (/* empty */)
//
#define _TRIGGER_PARENTHESIS_(...) , #define HAS_COMMA_EMPTY(...) HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__(/* empty */)) int main(int argc, char * argv[]) {
printf("%d\n", HAS_COMMA());
printf("%d\n", HAS_COMMA());
printf("%d\n", HAS_COMMA(, , , , , , , , , , , , , , ));
printf("%d\n", HAS_COMMA(, , , , , , , , , , , , , , , ));
printf("%d\n", HAS_COMMA(, , , , , , , , , , , , , , , , )); printf("%d\n", HAS_COMMA(,));
printf("%d\n", HAS_COMMA_EMPTY());
return ;
}
细细品味推荐的链接. 专业没那么简单 ~
后记 - 简单并不简单
下次再见, 有问题欢迎沟通交流指正 ~ 祝好运
音乐 : 约在春天相见
C 基础 _Generic 泛型应用的更多相关文章
- [.net 面向对象编程基础] (18) 泛型
[.net 面向对象编程基础] (18) 泛型 上一节我们说到了两种数据类型数组和集合,数组是指包含同一类型的多个元素,集合是指.net中提供数据存储和检索的专用类. 数组使用前需要先指定大小,并且检 ...
- 黑马程序员:Java基础总结----泛型(高级)
黑马程序员:Java基础总结 泛型(高级) ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 泛型(高级) 泛型是提供给javac编译器使用的,可以限定集合中的输入类型 ...
- Java基础:泛型
Java的泛型是什么呢, 就是类型的參数化,这得类型包含方法參数和返回值.也就是原本该是确定类型的地方换成了变量,把类型的确定时间向后延迟了. 在之前,学过"重载"的概念,重载是什 ...
- java基础(9) - 泛型解析
泛型 定义简单的泛型类 泛型方法 /** * 1.定义一个泛型类 * 在类名后添加类的泛型参数 <T> * 泛型类里面的所有T会根据创建泛型类时传入的参数确定类型 * 2.定义泛型方法 * ...
- Java基础之泛型
泛型: (1)为什么会出现泛型? 因为集合存放的数据类型不固定,故往集合里面存放元素时,存在安全隐患, 如果在定义集合时,可以想定义数组一样指定数据类型,那么就可以解决该类安全问题. JDK1.5后出 ...
- 【Java基础】泛型
Num1:请不要在新代码中使用原生类型 泛型类和接口统称为泛型.每种泛型定义一组参数化的类型,构成格式是:类或接口名称,接着用<>把对应于泛型形式类型的参数的实际参数列表括起来.比如:Li ...
- C#基础之泛型
1.泛型的本质 泛型的好处不用多说,在.NET中我看到有很多技术都是以泛型为基础的,不过因为不懂泛型而只能对那些技术一脸茫然.泛型主要用于集合类,最主要的原因是它不需要装箱拆箱且类型安全,比如很常用的 ...
- 黑马程序员——【Java基础】——泛型、Utilities工具类、其他对象API
---------- android培训.java培训.期待与您交流! ---------- 一.泛型 (一)泛型概述 1.泛型:JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制 ...
- Java基础之泛型——使用二叉树进行排序(TryBinaryTree)
控制台程序. 1.实现针对容器类的基于集合的循环 为了让容器类类型的对象能够在基于集合的for循环中可用,类必须并且只需要满足一个要求——必须实现泛型接口java.lang.Iterable<& ...
随机推荐
- drf序列化高级、自定义只读只写、序列化覆盖字段、二次封装Response、数据库查询优化(断关联)、十大接口、视图家族
目录 自定义只读 自定义只写 序列化覆盖字段 二次封装Response 数据库关系分析 断外键关联关系 ORM操作外键关系 ORM四种关联关系 基表 系列化类其他配置(了解) 十大接口 BaseSer ...
- Nginx是什么 ? 能干嘛 ?
学习博客:https://blog.csdn.net/forezp/article/details/87887507 学习博客:https://blog.csdn.net/qq_29677867/ar ...
- 一起了解 .Net Foundation 项目 No.6
.Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. .NET Micro Fr ...
- C语言基础五 数组的应用
.根据用户输入的10人成绩并将其保存到数组中,求最高成绩,最低成绩和平均成绩 int scoure[10];//存储10个数据的数组 int i; int sum;//总成绩 int max,min, ...
- JAVA架构之单点登录 任务调度 权限管理 性能优化大型项目实战
单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任.单点登录在大型网站里使用得 ...
- eclipse创建java和web工程
JAVA Eclipse→File→New→Project.. WEB 右键mvn项目→Properties src/main/webapp pom.xml <project xmlns=&qu ...
- pycharm中新建Vue项目时没有vue.js的解决办法
可能很多小伙伴在使用pycharm 1,新建vue项目的时候并没有发现vue.js的名字, 2,新建.vue文件(即单文件组件)的时候没有 下面就来帮助大家一下,仅供参考 如图: 1.首先我们打开设置 ...
- java Reflection(反射)基础知识讲解
原文链接:小ben马的java Reflection(反射)基础知识讲解 1.获取Class对象的方式 1.1)使用 "Class#forName" public static C ...
- neo4j学习摘要
参考 链接:https://gitbook.cn/books/5a33782c5778440a9d906017/index.html
- go 环境及4开发
国内加速 在gopath目录执行 go env -w GOPROXY=direct go env -w GOSUMDB=off go env -w GOPROXY=https://goproxy.io ...