一、通过宏定义的方式实现
#include <stdio.h>
#define Pair(T1, T2, ...) Pair$_##T1##_$$_##T2##_$##__VA_ARGS__
#define Pair_Def(T1, T2) \
typedef struct Pair(T1, T2) Pair(T1, T2); \
struct Pair(T1, T2) { \
T1 first; \
T2 second; \
}
typedef const char* Str;
Pair_Def(int, char);
Pair_Def(Str, float);
int main() {
// Pair(int, char)模仿C++的Pair<int, char>写法
// 该宏将被扩展为Pair$_int_$$_char_$
Pair(int, char) p1;
Pair(Str, float) p2;
p1.first = 123;
p1.second = 'a';
p2.first = "pi";
p2.second = 3.14f;
printf("p1: %d, %c\n", p1.first, p1.second);
printf("p2: %s, %f\n", p2.first, p2.second);
return 0;
}
二、通过_Generic关键字来实现
_Generic 是 C 语言中的一个关键字,用于声明泛型宏。泛型宏允许根据参数类型生成不同的代码。_Generic 关键字用于声明一个关联到类型的标识符列表。当宏被扩展时,标识符会被替换为与实际参数类型相对应的代码。
#define _Generic(type_var, generic_list) code
// generic_list 的格式为:
// type : code
// type : code
// ...
,我们可以实现一个泛型的 min 函数,返回两个值中的最小值:
c
#define min(a, b) _Generic((a), \
int : min_int, \
float : min_float, \
double : min_double \
)(a, b)
int min_int(int a, int b) { return a < b ? a : b; }
float min_float(float a, float b) { return a < b ? a : b; }
double min_double(double a, double b) { return a < b ? a : b; }
int main() {
int a = 1;
int b = 2;
printf("%d\n", min(a, b)); // 1
float c = 1.1;
float d = 2.2;
printf("%f\n", min(c, d));
使用 _Generic 关键字定义的泛型宏,其参数类型是可以不同的。当参数类型不同时,会选择与第一个参数相匹配的 case 语句。例如,我们可以这样定义 swap 泛型宏:
#define swap(a, b) _Generic((a), \
int : swap_int, \
float : swap_float, \
default : swap_double \
)(a, b)
void swap_int(int *a, int *b) { /* ... */ }
void swap_float(float *a, float *b) { /* ... */ }
void swap_double(double *a, double *b) { /* ... */ }
在这个定义中,如果 a 是 int 类型,那么选择 swap_int,如果 a 是 float 类型,那么选择 swap_float,否则选择 swap_double。所以我们可以这样调用:
int a = 1;
double b = 1.1;
swap(a, b); // 调用 swap_int(a, b)
float c = 1.1;
int d = 1;
swap(c, d); // 调用 swap_float(c, d)
因为第一个参数 a 是 int,所以选择 swap_int,而第一个参数 c 是 float,所以选择 swap_float。所以 _Generic 泛型宏可以支持参数类型不同的情况,它会根据第一个参数的类型来选择对应的实现。这为 C 语言带来更强大的泛型编程能力