扩展这个答案,关于多态解决方案,我们同样可以将其包括指针类型或用户定义的类型。这种方法的主要优点是摆脱“数据类型”枚举和所有运行时检查开关语句。
variant.h
#ifndef VARIANT_H
#define VARIANT_H
#include <stdio.h>
#include <stdint.h>
typedef void print_data_t (const void* data);
typedef void print_type_t (void);
typedef struct
{
void* data;
print_data_t* print_data;
print_type_t* print_type;
} variant_t;
void print_data_char (const void* data);
void print_data_short (const void* data);
void print_data_int (const void* data);
void print_data_ptr (const void* data);
void print_data_nothing (const void* data);
void print_type_char (void);
void print_type_short (void);
void print_type_int (void);
void print_type_int_p (void);
void print_type_void_p (void);
void print_type_void_f_void (void);
void print_data (const variant_t* var);
void print_type (const variant_t* var);
#define variant_init(var) { \
.data = &var, \
\
.print_data = _Generic((var), \
char: print_data_char, \
short: print_data_short, \
int: print_data_int, \
int*: print_data_ptr, \
void*: print_data_ptr, \
void(*)(void): print_data_nothing), \
\
.print_type = _Generic((var), \
char: print_type_char, \
short: print_type_short, \
int: print_type_int, \
int*: print_type_int_p, \
void*: print_type_void_p, \
void(*)(void): print_type_void_f_void) \
}
#endif
variant.c
#include "variant.h"
void print_data_char (const void* data) { printf("%c", *(const char*) data); }
void print_data_short (const void* data) { printf("%hd", *(const short*) data); }
void print_data_int (const void* data) { printf("%d", *(const int*) data); }
void print_data_ptr (const void* data) { printf("%p", data); }
void print_data_nothing (const void* data) {}
void print_type_char (void) { printf("char"); }
void print_type_short (void) { printf("short"); }
void print_type_int (void) { printf("int"); }
void print_type_int_p (void) { printf("int*"); }
void print_type_void_p (void) { printf("void*"); }
void print_type_void_f_void (void) { printf("void(*)(void)"); }
void print_data (const variant_t* var)
{
var->print_data(var->data);
}
void print_type (const variant_t* var)
{
var->print_type();
}
main.c
#include <stdio.h>
#include "variant.h"
int main (void)
{
char c = 'A';
short s = 3;
int i = 5;
int* iptr = &i;
void* vptr= NULL;
void (*fptr)(void) = NULL;
variant_t var[] =
{
variant_init(c),
variant_init(s),
variant_init(i),
variant_init(iptr),
variant_init(vptr),
variant_init(fptr)
};
for(size_t i=0; i<sizeof var / sizeof *var; i++)
{
printf("Type: ");
print_type(&var[i]);
printf("\tData: ");
print_data(&var[i]);
printf("\n");
}
return 0;
}
输出:
Type: char Data: A
Type: short Data: 3
Type: int Data: 5
Type: int* Data: 000000000022FD98
Type: void* Data: 000000000022FDA0
Type: void(*)(void) Data:
< p >使用
_Generic
的缺点是它会阻止我们使用私有封装,因为必须将其用作宏以传递类型信息。
另一方面,在这种情况下,“变量”必须针对所有新类型进行维护,因此并不是非常实用或通用。
尽管如此,了解这些技巧对于各种类似目的仍然是很有好处的。