Generic selection
通用选择
提供了一种在编译时根据控制表达式的类型选择多个表达式之一的方法。
句法
_Generic ( controlling-expression , association-list ) | | (since C11) |
---|
其中关联列表是以逗号分隔的关联列表,每个关联列表都有语法。
type-name : expression | | |
---|---|---|
default : expression | | |
其中
类型名 | - | 任何未经可变修改的完整对象类型(即不是VLA或指向VLA的指针)。 |
---|---|---|
控制表达 | - | 如果不使用默认关联,则其类型必须与其中一个类型名称兼容的任何表达式(逗号运算符除外) |
表达 | - | 任何类型和值类别的任何表达式(逗号运算符除外) |
关联列表中没有两个类型名称可以指定兼容类型。可能只有一个关联使用关键字default
。如果default
没有使用,并且没有任何类型名称与控制表达式的类型兼容,程序将不会编译。
说明
控制表达式的类型(在适用的情况下应用左值转换后(如果支持,请参阅下面的注释))与关联列表中的类型名称进行比较。
如果类型与其中一个关联的类型名称兼容,则泛型选择的类型,值和值类别是出现在该类型的冒号后面的表达式的类型,值和值类别 - 名称。
如果没有任何类型名称与控制表达式的类型兼容,并且default
提供了关联,则泛型选择的类型,值和值类别是表达式之后的类型,值和值类别该default :
标签。
笔记
控制表达式和未选择的选择表达式从不被评估。
控制表达式的左值转换仍然是一个未解决的问题(DR 431 / n1930):clang 不执行它们并按照原样使用左值的类型:"abc"
匹配char[4]
而不是char*
,(int const){0}
匹配const int
而不是int
)。同时,gcc执行控制表达式的左值转换(仅在类型域中:它放弃了顶级cvr限定符和原子性,或者将数组应用于控制表达式类型的指针/函数指针转换,而不启动任何副作用或计算任何值)。对于 GCC,"abc"
匹配char*
和char[4]
和(int const){0}
的比赛int
,而不是const int
。
所有值类别(包括函数指示符和无效表达式)都可以在通用选择中作为表达式使用,如果选择了,则通用选择本身具有相同的值类别。
<tgmath.h>在 C99中引入的类型通用数学宏以编译器特定的方式实现。在 C11中引入的通用选择为程序员提供了编写类似类型相关代码的能力。
泛型选择类似于C ++中的重载(其中几个函数中的一个是在编译时根据参数的类型选择的),除了它在任意表达式之间进行选择之外,与函数重载不同,函数可能具有不同的返回类型,甚至不同的价值类别。
关键词
_Generic
, default
.
例
#include <stdio.h>
#include <math.h>
// Possible implementation of the tgmath.h macro cbrt
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
/*for clang*/ const float: cbrtf, \
float: cbrtf \
)(X)
int main(void)
{
double x = 8.0;
const float y = 3.375;
printf("cbrt(8.0) = %f\n", cbrt(x) // selects the default cbrt
printf("cbrtf(3.375) = %f\n", cbrt(y) // gcc: converts const float to float,
// then selects cbrtf
// clang: selects cbrtf for const float
}
输出:
cbrt(8.0) = 2.000000
cbrtf(3.375) = 1.500000