有没有一种方法可以在C语言中实现模板效果?

3
我开发了一个包含简单链表函数的C dll,但它们都是在int类型上定义的。也就是说,每当用户使用我的库创建一个链表时,他只能创建一个int类型的列表。那么,如果我可以做一些事情(除了void *),让用户创建任意数据类型的列表,比如char、float甚至是用户定义的结构体呢?而且还不需要重新编译。
谢谢。

1
请注意,如果您的实现隐藏在预编译库中,即使是C++也无法帮助您。一般来说,C++模板需要存在于头文件中。 - Oliver Charlesworth
7个回答

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

除了 void * 之外,没有其他选择。

我想说的是,唯一的选择就是 void *

void * 是 C 中唯一的通用类型;在某种程度上,也是 C++ 中唯一的通用类型;因为它们都不被称为动态语言。

当然,如果你感觉特别疯狂,你可以重新调整内部链表链接的结构,包括一个联合,并命名一系列函数为

add_<type>_to_list(); // <type> = char, int, float

但这很可能无法得到令人满意的结果。


1

我同意其他答案,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))

1

我不是完全确定,但看起来这两个都是编译时特性;在运行时实际上并没有用处。 - Williham Totland
@Williham Totland:啊,那是C语言。除非你注释一些实现了运行时所需钩子的整数类型,否则你可以忘记识别'int'。你只能通过编译时来完成它。 - Matt Joiner
@Williham:如果使用Haskell作为参考,那么在编译时使用泛型可以做很多事情。如果将Nik的宏示例与类型上存在的数据结构相结合(有点像OCaml的函数),然后用一个“通用语句”重载其常见操作,你就可以走上一条动态感路线了。 - Eli

0

0

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

当然,宏不像模板那样类型安全,被认为是“不好的风格”。但是,我们在C语言中,谁会害怕宏呢?而且,void*也不是那么类型安全。


0
你可以在 C 语言中重写 C++ ,根据需要进行详细程度的控制。您可以从将链接列表的数据类型作为结构体*开始,转换为一些包装器结构,该结构本身可以包含类型标识符和指向实际数据的 void 指针。您可以编写自己的虚表以允许多态性,并添加引用计数和内存管理……如果您确实需要这种通用性,那么您肯定可以在 C 语言中编写所有内容。或者只需使用 C++ :-)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接