引言 - _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. Shell脚本 小程序演示

    一般的shell编程 场景贯穿了几个熟知的步骤: ●显示消息●获取用户输入●存储值到文件●处理存储的数据 这里写一个小程序 包含以上几部 #!/bin/bash while true do #echo ...

  2. Windows远程连接Ubuntu上的MySQL数据库

    原因:mysql安装好后,默认监听3306端口,并且只允许localhost访问,只允许root用户在localhost上登录.   我的环境:                 Ubuntu16.04 ...

  3. JS杨辉三角形

    题目:打印出杨辉三角形(要求打印出10行如下图) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 分析: 1.第1列或列数=行数时,value=1 2.其余的值 ...

  4. asp.net core 3.1 入口:Program.cs中的Main函数

    本文分析Program.cs 中Main()函数中代码的运行顺序分析asp.net core程序的启动,重点不是剖析源码,而是理清程序开始时执行的顺序.到底用了哪些实例,哪些法方. asp.net c ...

  5. jQuery on 绑定的事件 执行两次

    $(".class1").on("click",".class2",function(){ alert('提示'); }); 上面代码,怎么 ...

  6. JavaScript之DOM基础

    概述 DOM(Document Object Model)文档对象模型,针对Html和XML的文档的对象API,是一项 W3C (World Wide Web Consortium) 标准.文档对象模 ...

  7. springboot无法访问静态资源

    无法访问static下的静态资源 1.在application.yml中添加 resources: static-locations: classpath:/META-INF/resources/,c ...

  8. android编译/反编译常用工具及项目依赖关系

    项目依赖关系 apktool:依赖smali/baksmali,XML部分 AXMLPrinter2 JEB:dx 工具依赖 AOSP , 反编译dex 依赖 apktool dex2jar:依赖 A ...

  9. windows的启动、引导配置

    Win+S -> msconfig

  10. P2918 [USACO08NOV]买干草Buying Hay

    链接:Miku ---------------- 这就是一个完全背包的板子题 ---------------- 我们把重量当作重量,开销当作价值,那么这个题就是个求价值最小的完全背包 然而题目上说了是 ...