C11 引入关键字 _Generic,在编译期根据控制表达式的类型从候选列表中选择对应表达式,常用于宏中实现类型分派,在语法上接近 C++ 的函数重载,但与纯文本宏、类型别名的适用场景不同。

_Generic 表达式

_Generic 根据控制表达式的类型匹配关联类型,返回所选分支的表达式结果;控制表达式与未选中分支均不求值。

_Generic( (expression),
    type_1 : statements,
    type_2 : statements,
    ...
    default : statements
)

按类型选择整型常量

#include <stdio.h>

int main(void) {
    printf("%d\n", _Generic(1.0L, float : 1, double : 2,
                            long double : 3, default : 0));

    printf("%d\n", _Generic(1L, float : 1, double : 2,
                            long double : 3, default : 0));

    printf("%d\n", _Generic(1.0L, float : 1, double : 2,
                            long double : 3));
    return 0;
}

输出:

3
0
3

1.0L 的类型为 long double;1L 为 long,无对应项时走 default。

在宏中实现类型相关行为

#include <stdio.h>

#define typeName(T) _Generic((T), \
        char* : "String", \
        int : "Integer", \
        long : "Long Integer", \
        default : "Others")

int main(void) {
    printf("%s\n", typeName("A"));
    printf("%s\n", typeName(5));
    printf("%s", typeName(5.12));

    return 0;
}

输出:

String
Integer
Others

类型名称与数学函数分派

#include <stdio.h>

#define TYPE_NAME(X) _Generic((X), \
      int: "int", \
      char: "char", \
      double: "double", \
      default: "unknown")

int main(void) {
    printf("Type name: %s\n", TYPE_NAME(42));
    printf("Type name: %s\n", TYPE_NAME(42.42));
    printf("Type name: %s\n", TYPE_NAME('c'));
    return 0;
}

字符常量 'c' 在 C 中的类型为 int,故第三行输出 int。

标准头文件 tgmath.h 利用 _Generic 将泛型数学函数名映射到 float、double 等具体函数:

#define cbrt(X) _Generic((X), \
            long double: cbrtl, \
                default: cbrt,  \
                  float: cbrtf  \
            )(X)

#include <math.h>
#include <stdio.h>

int main(void) {
    double x = 8.0;
    const float y = 3.375;

    printf("cbrt(8.0) = %f\n", cbrt(x));
    printf("cbrtf(3.375) = %f\n", cbrt(y));
    return 0;
}

输出:

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

宏体末尾的 (X) 对所选函数指针进行调用,实参仅在最终调用时求值。

规则与限制

  • 关联列表中同一类型不得重复出现。
  • 不得同时列出互相兼容的类型(如枚举与其底层整型)。
  • 无 default 时,控制表达式类型须与某一关联类型完全匹配。
  • 匹配前会丢弃 const、volatile 等限定,并应用左值转换规则。

优缺点

  • 在宏层实现类型安全分派,减少手写多份函数。
  • 语法较复杂,错误信息可能难以阅读;宜用于库级抽象而非滥用。

本节说明了 _Generic 的语义及与宏的配合方式,可作为本章进阶主题的收束;继续学习时可结合标准库头文件与变参函数、格式说明符理解类型相关的 I/O 与泛型数学接口。