命名空间
变体
操作

通用选择 (自 C11 起)

来自 cppreference.com
< c‎ | 语言

提供了一种在编译时根据控制表达式的类型选择多个表达式中一个的方法

内容

[编辑] 语法

_Generic ( 控制表达式 , 关联列表 ) (自 C11 起)

其中 关联列表 是一个用逗号分隔的关联列表,每个关联都具有以下语法

类型名称 : 表达式
default : 表达式

其中

类型名称 - 任何非可变修饰的完整 对象类型(即,不是 VLA 或指向 VLA 的指针)。
控制表达式 - 任何表达式(除了 逗号运算符),其类型必须与其中一个 类型名称 兼容,前提是未使用 default 关联。
表达式 - 任何类型和值类别的任何表达式(除了 逗号运算符)。

关联列表 中的任何两个 类型名称 都不能指定 兼容类型。只有一个关联可以使用关键字 default。如果未使用 default,并且没有任何一个 类型名称 与控制表达式的类型兼容,则程序将无法编译。

[编辑] 解释

首先,控制表达式 的类型经历 左值转换。转换仅在类型域中执行:它会丢弃顶层 cvr 限定符和原子性,并对控制表达式的类型应用数组到指针/函数到指针转换,而不会启动任何副作用或计算任何值。

转换后的类型将与列表中关联的 类型名称 进行比较。

如果类型与其中一个关联的 类型名称 兼容,则通用选择的类型、值和 值类别 将是该 类型名称 后面冒号后面的 表达式 的类型、值和值类别。

如果没有任何一个 类型名称控制表达式 的类型兼容,并且提供了 default 关联,则通用选择的类型、值和值类别将是 default : 标记后面的表达式的类型、值和值类别。

[编辑] 备注

控制表达式 和未选中的选择的 表达式 永远不会求值。

由于左值转换,"abc"char* 匹配,而不是与 char[4] 匹配,并且 (int const){0}int 匹配,而不是与 const int 匹配。

所有 值类别(包括函数指示符和 void 表达式)都允许作为通用选择中的 表达式,如果被选中,通用选择本身将具有相同的 value 类别。

来自 <tgmath.h>类型通用数学宏(在 C99 中引入)是通过编译器特定方式实现的。在 C11 中引入的通用选择使程序员能够编写类似的类型相关代码。

通用选择类似于 C++ 中的重载(在编译时根据参数的类型选择多个函数中的一个),不同之处在于它可以在任意表达式之间进行选择。

[编辑] 关键字

_Genericdefault

[编辑] 示例

#include <math.h>
#include <stdio.h>
 
// Possible implementation of the tgmath.h macro cbrt
#define cbrt(X) _Generic((X), \
              long double: cbrtl, \
                  default: cbrt,  \
                    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)); // converts const float to float,
                                            // then selects cbrtf
}

输出

cbrt(8.0) = 2.000000
cbrtf(3.375) = 1.500000

[编辑] 缺陷报告

以下行为更改缺陷报告已追溯应用于先前发布的 C 标准。

DR 应用于 已发布的行为 正确行为
DR 481 C11 控制表达式是否经历左值转换尚不清楚 经历了

[编辑] 参考文献

  • C23 标准 (ISO/IEC 9899:2024)
  • 6.5.1.1 通用选择 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018)
  • 6.5.1.1 通用选择 (p: 56-57)
  • C11 标准 (ISO/IEC 9899:2011)
  • 6.5.1.1 通用选择 (p: 78-79)

[编辑] 参见

C++ 文档 用于 模板