Apple LLVM4.0已经支持了C11标准中的关键特性——泛型机制。尽管C11中的泛型机制比起C++的来要显得简陋不少,但是在做库的时候仍然十分管用。
下面我们就来看一下C11标准中的泛型表达式。
C11中的泛型机制由关键字_Generic引出,其语法形式为:
_Generic ( assignment-expression , generic-assoc-list )
generic-assoc-list:
generic-association
generic-assoc-list , generic-association
generic-association:
type-name : assignment-expression
default : assignment-expression
下面给出C代码例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#define GENERAL_ABS(x) _Generic((x), int:abs, float:fabsf, double:fabs)(x)
static
void
GenericTest(
void
)
{
printf
(
"int abs: %d\n"
, GENERAL_ABS(-12));
printf
(
"float abs: %f\n"
, GENERAL_ABS(-12.04f));
printf
(
"double abs: %f\n"
, GENERAL_ABS(-13.09876));
int
a = 10;
int
b = 0, c = 0;
_Generic(a + 0.1f,
int
:b,
float
:c,
default
:b)++;
printf
(
"b = %d, c = %d\n"
, b, c);
_Generic(a += 1.1f,
int
:b,
float
:c,
default
:b)++;
printf
(
"a = %d, b = %d, c = %d\n"
, a, b, c);
}
|
这边要注意的是,_Generic里的assignment-expression只获取其类型而不会对它做运行时计算。也就是说,编译器仅仅在编译时获得该表达式的类型,而不会产生任何其它指令。这个跟sizeof()、typeof(),以及C++中的typeid()和decltype()一样。
另外,generic-association-list中必须要有与assignment-expression类型相同的generic-association,否则编译会报错。当然,如果在generic-association-list中含有default处理,那么编译能顺利进行。如以下代码所示:
1
2
3
4
5
6
7
|
struct
MyStruct {
int
a, b; } s;
_Generic(
"Hello"
,
const
char
*:
puts
(
"OK!"
));
// ERROR! "Hello"为char[6]类型
_Generic(
"Hello"
,
char
[6]:
puts
(
"OK!"
));
// OK
_Generic((
const
char
*)
"Hello"
,
const
char
*:
puts
(
"OK!"
));
// OK
_Generic(s,
int
:
puts
(
"OK!"
));
// ERROR
_Generic(s,
struct
MyStruct:
puts
(
"OK!"
));
// OK
_Generic(s,
int
:
puts
(
"Yep!"
),
default
:
puts
(
"Others"
));
// OK
|