我听说C11添加了泛型。我查了一下谷歌,看了一些文章,了解到有一个新的关键字(_Generic
)等等。但我好像还是无法完全理解。
它是否类似于C#中的泛型或C ++中的模板?能否给我简要解释一下C11泛型的定义、语法和一个简单的使用示例?
我看过的最好的例子启发了下面(可运行)的示例,它为疯狂的内省解锁了各种奇怪的可能性...
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#define typename(x) _Generic((x), /* Get the name of a type */ \
\
_Bool: "_Bool", unsigned char: "unsigned char", \
char: "char", signed char: "signed char", \
short int: "short int", unsigned short int: "unsigned short int", \
int: "int", unsigned int: "unsigned int", \
long int: "long int", unsigned long int: "unsigned long int", \
long long int: "long long int", unsigned long long int: "unsigned long long int", \
float: "float", double: "double", \
long double: "long double", char *: "pointer to char", \
void *: "pointer to void", int *: "pointer to int", \
default: "other")
#define fmt "%20s is '%s'\n"
int main() {
size_t s; ptrdiff_t p; intmax_t i; int ai[3] = {0}; return printf( fmt fmt fmt fmt fmt fmt fmt fmt,
"size_t", typename(s), "ptrdiff_t", typename(p),
"intmax_t", typename(i), "character constant", typename('0'),
"0x7FFFFFFF", typename(0x7FFFFFFF), "0xFFFFFFFF", typename(0xFFFFFFFF),
"0x7FFFFFFFU", typename(0x7FFFFFFFU), "array of int", typename(ai));
}
╔═══════════════╗
═════════════════╣ Amazeballs... ╠═════════════════════════════════════
╚═══════════════╝
size_t is 'unsigned long int'
ptrdiff_t is 'long int'
intmax_t is 'long int'
character constant is 'int'
0x7FFFFFFF is 'int'
0xFFFFFFFF is 'unsigned int'
0x7FFFFFFFU is 'unsigned int'
array of int is 'other'
const
、volatile
和volatile const
)时,就会得到64个不同的变体。虽然繁琐,但并非不可能。每种类型的指针会使这个数字翻倍,而指向指针的指针会进一步增加它......但这样总共只有192个变体......唉!但仍然不是不可能的。 - SGeorgiades这篇文章是一个非常好的介绍。以下是概述:
通用选择使用新关键字实现:_Generic。语法类似于类型的简单switch语句:
_Generic('a',char:1,int:2,long:3,default:0)
评估为2(C中的字符常量是int)。
基本上,它像一种switch
,其中标签是类型名称,其针对第一个表达式(上面的'a'
)进行测试。结果成为评估_Generic()
的结果。
我使用的是CLion 1.2.4版本,但是它目前不支持C11语法,因此我使用GNU C99中的以下代码替代了_Generic
。
#include <stdio.h>
int main(int argc, char **argv) {
char *s;
if (__builtin_types_compatible_p(__typeof__(s), long)) {
puts("long");
} else if (__builtin_types_compatible_p(__typeof__(s), char*)) {
puts("str");
}
return (0);
};