引言 - _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 泛型应用的更多相关文章

  1. [.net 面向对象编程基础] (18) 泛型

    [.net 面向对象编程基础] (18) 泛型 上一节我们说到了两种数据类型数组和集合,数组是指包含同一类型的多个元素,集合是指.net中提供数据存储和检索的专用类. 数组使用前需要先指定大小,并且检 ...

  2. 黑马程序员:Java基础总结----泛型(高级)

    黑马程序员:Java基础总结 泛型(高级)   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 泛型(高级) 泛型是提供给javac编译器使用的,可以限定集合中的输入类型 ...

  3. Java基础:泛型

    Java的泛型是什么呢, 就是类型的參数化,这得类型包含方法參数和返回值.也就是原本该是确定类型的地方换成了变量,把类型的确定时间向后延迟了. 在之前,学过"重载"的概念,重载是什 ...

  4. java基础(9) - 泛型解析

    泛型 定义简单的泛型类 泛型方法 /** * 1.定义一个泛型类 * 在类名后添加类的泛型参数 <T> * 泛型类里面的所有T会根据创建泛型类时传入的参数确定类型 * 2.定义泛型方法 * ...

  5. Java基础之泛型

    泛型: (1)为什么会出现泛型? 因为集合存放的数据类型不固定,故往集合里面存放元素时,存在安全隐患, 如果在定义集合时,可以想定义数组一样指定数据类型,那么就可以解决该类安全问题. JDK1.5后出 ...

  6. 【Java基础】泛型

    Num1:请不要在新代码中使用原生类型 泛型类和接口统称为泛型.每种泛型定义一组参数化的类型,构成格式是:类或接口名称,接着用<>把对应于泛型形式类型的参数的实际参数列表括起来.比如:Li ...

  7. C#基础之泛型

    1.泛型的本质 泛型的好处不用多说,在.NET中我看到有很多技术都是以泛型为基础的,不过因为不懂泛型而只能对那些技术一脸茫然.泛型主要用于集合类,最主要的原因是它不需要装箱拆箱且类型安全,比如很常用的 ...

  8. 黑马程序员——【Java基础】——泛型、Utilities工具类、其他对象API

    ---------- android培训.java培训.期待与您交流! ---------- 一.泛型 (一)泛型概述 1.泛型:JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制 ...

  9. Java基础之泛型——使用二叉树进行排序(TryBinaryTree)

    控制台程序. 1.实现针对容器类的基于集合的循环 为了让容器类类型的对象能够在基于集合的for循环中可用,类必须并且只需要满足一个要求——必须实现泛型接口java.lang.Iterable<& ...

随机推荐

  1. df du 文件空间管理 命令

     df  可以查看一级文件夹大小.使用比例.档案系统及其挂入点,但对文件却无能为力. du 可以查看文件及文件夹的大小.     df:常用   df -h    以易读形式显示 磁盘空间 linux ...

  2. 论文翻译:Speech Enhancement Based on the General Transfer Function GSC and Postfiltering

    论文地址:基于通用传递函数GSC和后置滤波的语音增强 博客作者:凌逆战 博客地址:https://www.cnblogs.com/LXP-Never/p/12232341.html 摘要 在语音增强应 ...

  3. Webpack实战(八):教你搞懂webpack如果实现代码分片(code splitting)

    2020年春节已过,本来打算回郑州,却因为新型冠状病毒感染肺炎的疫情公司推迟了上班的时间,我也推迟了去郑州的时间,在家多陪娃几天.以前都是在书房学习写博客,今天比较特殊,抱着电脑,在楼顶晒着太阳,陪着 ...

  4. 聊聊spring之bean对象的实例化过程

    在spring实例化 之前bean对象封装成 beanDefinition 对象 想了解详情的请参考上一篇文章 好了 我们聊聊 Bean 的实例化过程的几个重要角色 BeanDefinitionReg ...

  5. mysql必知必会--联 结 表

    联结 SQL最强大的功能之一就是能在数据检索查询的执行中联结(join) 表.联结是利用SQL的 SELECT 能执行的最重要的操作,很好地理解联结 及其语法是学习SQL的一个极为重要的组成部分 外键 ...

  6. .net对象与IntPtr"互转"

    写于2015-1-29 16:17 由qq空间转过来,格式有点乱 "互转"这里其实只是GC分配的一个IntPtr,通过这个IntPtr引用操作而真正的托管对象与非托管对象的互转应使 ...

  7. 题解 Luogu P3370

    讲讲这题的几种做法: 暴力匹配法 rt,暴力匹配,即把字符串存起来一位一位判相等 时间复杂度$ O(n^2·m) $ 再看看数据范围 \(n\le10^5,m\le10^3\) 当场爆炸.当然有暴力分 ...

  8. 一、threejs————灯光阴影

    threejs设置阴影有三个注意点 1.只有支持阴影的灯光才可以 pointLight,spotlight,directionallight 2.添加摄像机辅助器 THREE.CameraHelper ...

  9. Dolphin Scheduler初始化Postgresql数据库失败

    在执行sh script/create-dolphinscheduler.sh初始化数据库时报错: 07:05:03.070 [main] ERROR com.alibaba.druid.pool.D ...

  10. MySQL 当记录不存在时插入(insert if not exists、dual )

    INSERT INTO clients(client_id, client_name, client_type)SELECT 10345, ’IBM’, ’advertising’FROM dualW ...