我开发了一个包含简单链表函数的C dll,但它们都是在int类型上定义的。也就是说,每当用户使用我的库创建一个链表时,他只能创建一个int类型的列表。那么,如果我可以做一些事情(除了void *),让用户创建任意数据类型的列表,比如char、float甚至是用户定义的结构体呢?而且还不需要重新编译。
谢谢。
谢谢。
使用宏是一种不错的模板化定义方法,即基于模式生成任意数量的定义。这里有一个例子——但它非常丑陋。
#include <stdlib.h>
#define template_struct_A(T1,T2) struct A_ ## T1 ## _ ## T2 { \
T1 a; \
T2 b; \
}
#define struct_A(T1,T2) struct A_ ## T1 ## _ ## T2
struct C { const char*s; };
typedef const char* pchar;
template_struct_A(int, pchar); // explicit instantiation of struct A<int, pchar>
int main() {
struct X { struct C x; } x;
struct_A(int, pchar) o1; // struct A<int, const char*> o1
o1.a = 1;
o1.b = "hello";
struct_A(int, pchar) o2; // struct A<int, const char*> o2
o2.a = o1.a * 2;
o2.b = "world";
typedef struct_A(int, pchar)* pAInt;
typedef struct C structC;
template_struct_A(pAInt, structC) o3; // struct A<struct A<int, const char*>, struct C> o3
o3.a = &o2;
o3.b.s = "hi";
printf ("o1.a = %d, o1.b = %s, o2.a = %d, o2.b = %s, o3.b.s = %s\n", o1.a, o1.b, o2.a, o2.b, o3.b.s);
}
除了 void *
之外,没有其他选择。
我想说的是,唯一的选择就是 void *
。
void *
是 C 中唯一的通用类型;在某种程度上,也是 C++ 中唯一的通用类型;因为它们都不被称为动态语言。
当然,如果你感觉特别疯狂,你可以重新调整内部链表链接的结构,包括一个联合,并命名一系列函数为
add_<type>_to_list(); // <type> = char, int, float…
但这很可能无法得到令人满意的结果。
我同意其他答案,void *
是唯一的选择。但是如果您添加一个大小参数来指示 void *
指向多少字节,您可以在不重新编译的情况下挤出更多的动态行为。
void *shift(list *plist, unsigned size);
void unshift(list *plist, void *item, unsigned size);
然后你可以使用宏来隐藏大小。
#define Cshift(L) shift(L,sizeof(char))
#define Cunshift(L,I) unshift(L,I,sizeof(char))
在运行时没有办法不使用 void * 来实现它。但是有一种方法可以在不需要单独编译代码的情况下实现:所有操作都可以使用 #define。
您可以使用宏。例如,您可以创建不同的列表节点类型,具有不同类型的data
成员,并确保所有节点都具有next
和prev
成员。然后,只需使用宏执行所有列表操作(如添加、插入、删除),因为这些操作不关心存储的类型。
当然,宏不像模板那样类型安全,被认为是“不好的风格”。但是,我们在C语言中,谁会害怕宏呢?而且,void*
也不是那么类型安全。
结构体*
开始,转换为一些包装器结构,该结构本身可以包含类型标识符和指向实际数据的 void 指针。您可以编写自己的虚表以允许多态性,并添加引用计数和内存管理……如果您确实需要这种通用性,那么您肯定可以在 C 语言中编写所有内容。或者只需使用 C++ :-)