有没有办法在C中获得模板效果?

时间:2011-06-24 11:32:00

标签: c data-structures

我开发了一个包含简单链接列表函数的C dll,但它们都是在int类型上定义的,即当用户使用我的库创建链接列表时,他只能创建一个int列表。所以如果我能做一些事情(void *除外)让用户创建一个任意数据类型的列表,比如char,float甚至用户定义struct?这也没有重新编译。

感谢。

7 个答案:

答案 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。

http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/queue.h?rev=1.75;content-type=text%2Fx-cvsweb-markup

答案 5 :(得分:0)

您可以使用宏。例如,您可以使用不同类型的data成员制作不同的列表节点类型,并确保所有成员都有nextprev成员。然后只对所有列表操作使用宏(如添加,插入,删除),因为这些操作不关心存储的类型。

当然,宏并不像模板那样安全,被认为是“糟糕的风格”。但是,嘿,我们在C,谁担心C中的宏? void*也不是那种类型的安全。

答案 6 :(得分:0)

你基本上可以用C语言重写C ++,无论你需要什么级别的细节。您可以首先将链表的数据类型设置为struct *到某个包装器结构,该结构本身可以包含类型标识符和指向实际数据的void指针。您可以编写自己的vtable以允许多态,并且您可以添加引用计数和内存管理...这些都不是魔术,所以如果您真的需要那种通用性,那么您当然可以用C语言编写它。或者只是使用C ++: - )