我开发了一个包含简单链接列表函数的C dll,但它们都是在int类型上定义的,即当用户使用我的库创建链接列表时,他只能创建一个int列表。所以如果我能做一些事情(void *除外)让用户创建一个任意数据类型的列表,比如char,float甚至用户定义struct?这也没有重新编译。
感谢。
答案 0 :(得分:3)
使用宏是模板化定义的一种不错的方法,即根据模式生成任意数量的定义。这是一个例子 - 但它很丑陋。
#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);
}
答案 1 :(得分:1)
除了void *
之外,唯一的选择是,没有。
唯一的选择是void *
,就是我所说的。
void *
是C中唯一的泛型类型;在某种程度上,也是C ++中唯一的通用学位;因为你不会称之为动态语言。
当然,如果你感觉特别疯狂,你可以重新调整你的内部结构链接列表链接以包含一个联合,并有一系列名为
的函数add_<type>_to_list(); // <type> = char, int, float…
但这不太可能给人满意的结果。
答案 2 :(得分:1)
答案 3 :(得分:1)
我同意其他答案,void *
是唯一的出路。但是,如果添加一个指示void *
指向的字节数的size参数,则可以在不重新编译的情况下挤出更多动态行为。
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))
答案 4 :(得分:0)
没有void *,没有办法在运行时执行此操作。但是没有单独编译的代码就可以做到这一点:所有操作都可以是#define。
答案 5 :(得分:0)
您可以使用宏。例如,您可以使用不同类型的data
成员制作不同的列表节点类型,并确保所有成员都有next
和prev
成员。然后只对所有列表操作使用宏(如添加,插入,删除),因为这些操作不关心存储的类型。
当然,宏并不像模板那样安全,被认为是“糟糕的风格”。但是,嘿,我们在C,谁担心C中的宏? void*
也不是那种类型的安全。
答案 6 :(得分:0)
你基本上可以用C语言重写C ++,无论你需要什么级别的细节。您可以首先将链表的数据类型设置为struct *
到某个包装器结构,该结构本身可以包含类型标识符和指向实际数据的void指针。您可以编写自己的vtable以允许多态,并且您可以添加引用计数和内存管理...这些都不是魔术,所以如果您真的需要那种通用性,那么您当然可以用C语言编写它。或者只是使用C ++: - )