C 基础 _Generic 泛型应用
Posted life2refuel
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 0; }
正文 - _Generic 实现函数重载
#include <stdio.h> void foo_void(void) { printf("void "); } void foo_int(int c) { printf("int: %d ", c); } void foo_char(char c) { printf("char: %c ", c); } void foo_double(double c) { printf("double: %f ", c); } void foo_double_int(double c, int d) { printf("double: %f, int: %d ", 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__) 3, 2, 1, 0) #define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 0) #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(7); foo(10.12); foo(12.10, 7); foo((char)‘s‘); return 0; }
{
代码脉络可以详细参照下面 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 ", HAS_COMMA()); printf("%d ", HAS_COMMA(1)); printf("%d ", HAS_COMMA(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); printf("%d ", HAS_COMMA(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); printf("%d ", HAS_COMMA(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)); printf("%d ", HAS_COMMA(,)); printf("%d ", HAS_COMMA_EMPTY()); return 0; }
细细品味推荐的链接. 专业没那么简单 ~
后记 - 简单并不简单
下次再见, 有问题欢迎沟通交流指正 ~ 祝好运
音乐 : 约在春天相见
以上是关于C 基础 _Generic 泛型应用的主要内容,如果未能解决你的问题,请参考以下文章
[Unity] C#中级编程 - 04 - 泛型/构造函数/ref