C | _Generic泛型选择

Jul 25, 2025
#c

Notion链接

_Generic 在 C 语言中被称为泛型选择(Generic Selection)或类型泛型表达式。这是 C11 标准引入的特性。

  • 主要用于类型感知的宏编程,实现类似函数重载的效果
  • 编译时处理,编译器会直接替换为对应的表达式
  • 基于类型进行选择
  • 是一个表达式,会被替换为某个值

示例:

// 编译时根据类型选择
int i = 10;
char *result = _Generic(i,
    int: "integer",
    float: "float",
    default: "other"
);
// 编译后直接变成:char *result = "integer";

_Generic 是一个表达式,不是语句,错误示例:

// ❌ 错误!不能写多行代码
int i = 10;
char *result = _Generic(i,
    int: {
        printf("It's an integer\\n");  // 编译错误
        return "integer";
    },
    float: "float",
    default: "other"
);

多行逻辑解决办法

1. 使用函数调用

char* handle_int() {
    printf("Processing integer\n");
    // 可以有复杂逻辑
    return "integer";
}

char* handle_float() {
    printf("Processing float\n");
    return "float";
}

int i = 10;
char *result = _Generic(i,
    int: handle_int(),      // 调用函数
    float: handle_float(),
    default: "other"
);

2. 使用逗号运算符

int i = 10;
char *result = _Generic(i,
    int: (printf("It's an integer\n"), "integer"),  // 逗号运算符
    float: (printf("It's a float\n"), "float"),
    default: "other"
);

3. 结合条件表达式

int i = 10;
char *result = _Generic(i,
    int: i > 0 ? "positive integer" : "non-positive integer",
    float: "float",
    default: "other"
);

4. 如果需要复杂逻辑,建议用宏包装

#define HANDLE_TYPE(x) do { \\
    char *result = _Generic((x), \\
        int: handle_int(), \\
        float: handle_float(), \\
        default: "other" \\
    ); \\
    /* 在这里可以添加更多处理逻辑 */ \\
    printf("Result: %s\n", result); \\
} while(0)

// 使用
int i = 10;
HANDLE_TYPE(i);

完整示例

示例1:

#include <stdio.h>

#define TYPE_NAME(x) _Generic((x), \
    int: "integer", \
    float: "float", \
    double: "double", \
    char: "character", \
    char*: "string", \
    default: "unknown type" \
)

int main(void)
{
    int num = 100;
    float pi = 3.14159f;
    double e = 2.71828;
    char letter = 'Z';
    char *message = "Hello";
    
    printf("num (%d) is a %s\n", num, TYPE_NAME(num));
    printf("pi (%.2f) is a %s\n", pi, TYPE_NAME(pi));
    printf("e (%.5f) is a %s\n", e, TYPE_NAME(e));
    printf("letter ('%c') is a %s\n", letter, TYPE_NAME(letter));
    printf("message (\"%s\") is a %s\n", message, TYPE_NAME(message));
    
    return 0;
}

输出:

num (100) is a integer
pi (3.14) is a float
e (2.71828) is a double
letter ('Z') is a character
message ("Hello") is a string

示例2:

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

// 为不同类型定义不同的处理函数
int process_int(int x) {
    printf("Processing integer: %d\n", x);
    return x * x;  // 返回平方
}

float process_float(float x) {
    printf("Processing float: %.2f\n", x);
    return sqrtf(x);  // 返回平方根
}

double process_double(double x) {
    printf("Processing double: %.6f\n", x);
    return log(x);  // 返回自然对数
}

char process_char(char x) {
    printf("Processing character: '%c'\n", x);
    return x >= 'a' && x <= 'z' ? x - 32 : x;  // 小写转大写
}

void process_default(void) {
    printf("Processing unsupported type\n");
}

// 使用 _Generic 创建泛型处理宏
#define PROCESS(x) _Generic((x), \
    int:    process_int, \
    float:  process_float, \
    double: process_double, \
    char:   process_char, \
    default: process_default \
)(x)

// 另一个例子:类型泛型的比较函数
#define MAX(a, b) _Generic((a) + (b), \
    int:    ((int)(a) > (int)(b) ? (int)(a) : (int)(b)), \
    float:  ((float)(a) > (float)(b) ? (float)(a) : (float)(b)), \
    double: ((double)(a) > (double)(b) ? (double)(a) : (double)(b)), \
    default: 0 \
)

// 类型泛型的格式化输出
#define PRINT_VALUE(x) _Generic((x), \
    int:    printf("Integer: %d\n", (x)), \
    float:  printf("Float: %.2f\n", (x)), \
    double: printf("Double: %.6f\n", (x)), \
    char:   printf("Character: '%c' (ASCII: %d)\n", (x), (int)(x)), \
    char*:  printf("String: \"%s\"\n", (x)), \
    default: printf("Unknown type\n") \
)

int main(void)
{
    printf("=== 泛型处理函数示例 ===\n");
    
    int i = 5;
    float f = 16.0f;
    double d = 2.718281828;
    char c = 'h';
    
    printf("Original values:\n");
    PRINT_VALUE(i);
    PRINT_VALUE(f);
    PRINT_VALUE(d);
    PRINT_VALUE(c);
    
    printf("\nProcessing results:\n");
    int result_i = PROCESS(i);
    float result_f = PROCESS(f);
    double result_d = PROCESS(d);
    char result_c = PROCESS(c);
    
    printf("\nProcessed values:\n");
    PRINT_VALUE(result_i);
    PRINT_VALUE(result_f);
    PRINT_VALUE(result_d);
    PRINT_VALUE(result_c);
    
    printf("\n=== 泛型最大值函数示例 ===\n");
    
    int max_int = MAX(10, 25);
    float max_float = MAX(3.14f, 2.71f);
    double max_double = MAX(1.234567, 1.234568);
    
    printf("MAX(10, 25) = %d\n", max_int);
    printf("MAX(3.14f, 2.71f) = %.2f\n", max_float);
    printf("MAX(1.234567, 1.234568) = %.6f\n", max_double);
    
    printf("\n=== 混合类型示例 ===\n");
    
    char *str = "Hello World";
    long long big_num = 9876543210LL;
    
    PRINT_VALUE(str);
    PRINT_VALUE(big_num);  // 会触发 default 情况
    
    return 0;
}

输出:

=== 泛型处理函数示例 ===
Original values:
Integer: 5
Float: 16.00
Double: 2.718282
Character: 'h' (ASCII: 104)

Processing results:
Processing integer: 5
Processing float: 16.00
Processing double: 2.718282
Processing character: 'h'

Processed values:
Integer: 25
Float: 4.00
Double: 1.000000
Character: 'H' (ASCII: 72)

=== 泛型最大值函数示例 ===
MAX(10, 25) = 25
MAX(3.14f, 2.71f) = 3.14
MAX(1.234567, 1.234568) = 1.234568

=== 混合类型示例 ===
String: "Hello World"
Unknown type

  • https://en.cppreference.com/w/c/language/generic.html
  • Claude Sonnet 4 Thinking
https://inasa.dev/posts/rss.xml