C 语言之泛型编程


C11 标准引入了一些新的特性,使得在 C 语言中实现泛型编程变得更加容易。本文将探讨如何利用 C11 的 _Generic 关键字和其他特性来实现泛型编程。

什么是泛型编程

泛型编程是一种编程范式,旨在编写与特定数据类型无关的代码,从而提高代码的复用性和灵活性。在 C++ 中,模板提供了直接支持泛型编程的语法。而在 C 中,C11 标准的新特性使我们能够实现类似的功能。

C11 的 _Generic 关键字

C11 标准引入了 _Generic 关键字,它允许根据表达式的类型选择不同的代码路径。这为在 C 中实现泛型编程提供了强大的工具。

基本用法

以下是 _Generic 关键字的基本用法示例:

#include <stdio.h>

#define type_name(x) _Generic((x),                \
    int: "int",                                   \
    float: "float",                               \
    double: "double",                             \
    default: "unknown")

int main() {
    int i = 0;
    float f = 0.0;
    double d = 0.0;
    char c = 'a';

    printf("i is of type %s\n", type_name(i));
    printf("f is of type %s\n", type_name(f));
    printf("d is of type %s\n", type_name(d));
    printf("c is of type %s\n", type_name(c));

    return 0;
}

输出结果:

i is of type int
f is of type float
d is of type double
c is of type unknown

实现泛型函数

我们可以利用 _Generic 实现类似于 C++ 模板的泛型函数。例如,我们可以实现一个泛型的 max 函数,根据参数的类型选择不同的比较函数:

#include <stdio.h>

#define max(a, b) _Generic((a),        \
    int: max_int,                      \
    float: max_float,                  \
    double: max_double                 \
)(a, b)

int max_int(int a, int b) {
    return a > b ? a : b;
}

float max_float(float a, float b) {
    return a > b ? a : b;
}

double max_double(double a, double b) {
    return a > b ? a : b;
}

int main() {
    int i1 = 10, i2 = 20;
    float f1 = 10.5, f2 = 20.5;
    double d1 = 10.5, d2 = 20.5;

    printf("max(i1, i2) = %d\n", max(i1, i2));
    printf("max(f1, f2) = %f\n", max(f1, f2));
    printf("max(d1, d2) = %f\n", max(d1, d2));

    return 0;
}

输出结果:

max(i1, i2) = 20
max(f1, f2) = 20.500000
max(d1, d2) = 20.500000

泛型数据结构

我们还可以使用 _Generic 和 void* 实现泛型数据结构。例如,下面是一个简单的泛型链表实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Node {
    void *data;
    struct Node *next;
} Node;

Node* create_node(void *data, size_t data_size) {
    Node *new_node = (Node*)malloc(sizeof(Node));
    new_node->data = malloc(data_size);
    new_node->next = NULL;
    memcpy(new_node->data, data, data_size);
    return new_node;
}

void push(Node **head_ref, void *new_data, size_t data_size) {
    Node *new_node = create_node(new_data, data_size);
    new_node->next = *head_ref;
    *head_ref = new_node;
}

void print_list(Node *node, void (*print_fn)(void *)) {
    while (node != NULL) {
        print_fn(node->data);
        node = node->next;
    }
}

void print_int(void *n) {
    printf("%d ", *(int *)n);
}

void print_float(void *f) {
    printf("%f ", *(float *)f);
}

#define print_list_generic(list, type) _Generic((type), \
    int: print_list(list, print_int),                   \
    float: print_list(list, print_float)                \
)

int main() {
    Node *int_list = NULL;
    int int_arr[] = {10, 20, 30, 40, 50};
    size_t int_n = sizeof(int_arr) / sizeof(int_arr[0]);

    for (size_t i = 0; i < int_n; i++) {
        push(&int_list, &int_arr[i], sizeof(int));
    }

    printf("Integer linked list: ");
    print_list_generic(int_list, int);
    printf("\n");

    Node *float_list = NULL;
    float float_arr[] = {10.1, 20.2, 30.3, 40.4, 50.5};
    size_t float_n = sizeof(float_arr) / sizeof(float_arr[0]);

    for (size_t i = 0; i < float_n; i++) {
        push(&float_list, &float_arr[i], sizeof(float));
    }

    printf("Float linked list: ");
    print_list_generic(float_list, float);
    printf("\n");

    return 0;
}

输出结果:

Integer linked list: 50 40 30 20 10 
Float linked list: 50.500000 40.400002 30.299999 20.200001 10.100000 

总结

C11 标准的新特性,特别是 _Generic 关键字,使得在 C 语言中实现泛型编程变得更加容易。通过结合使用宏定义、void* 和 _Generic,我们可以编写出与特定数据类型无关的代码,从而提高代码的复用性和灵活性。

希望这篇博客能帮助您理解如何在 C11 中实现泛型编程。如果您有任何问题或建议,欢迎在评论区留言讨论。

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值