C,概括函数参数的类型

我正在为链表和树编写ac库,我正在寻找一种解决方案来概括这些库处理的数据类型,而不需要为我需要处理的每种类型创建一个列表/树库。

例如,我的列表库具有以下function:

/* list.h */ typedef int list_element; // <-- need to generalize that struct list_node { list_element value; struct list_node* next; }; typedef struct list_node list_node; typedef struct list_node* list; extern list list_cons(list_element d, list l) 

然后我的list.c:

 /* list.c */ #include  list list_cons(list_element d, list l){ list m = malloc(sizeof(list_node)); m->value = element_copy(d); m->next = l; return m; } 

现在假设在我的主程序中我要使用int列表和double列表,我应该创建2个文件,比如list_float.c / .h和list_int.c / .h
还有一些list_element可以是struct,需要像copy / isLess / isEqual这样的函数来比较自己我想在我的代码中写这样的东西:

 /* main.c */ list_cons(void *data, list l); 

如果data是指向我想要的任何类型的指针,并且在list_conselement_copy适用于我传递的任何类型的数据(显然我需要复制数据而不是指向数据的指针,void *是我必须概括参数类型的唯一想法)一个function)

作为一般建议,您不应该假设list_cons是构建链表的唯一方法。 有时malloc不可用或用户想要在静态数组中预分配所有内容或想要使用自定义分配器或…

作为具体示例,您可以查看https://github.com/torvalds/linux/blob/master/include/linux/list.h 。

如果您需要代码的其他许可证,请在xBSD Unix源代码中搜索数据结构实现。

一般的想法是,您只需要一个链表结构来包含next / prev和类似字段,而不是限制用户使用您的类型名称。 所有迭代和基本操作都被定义为预处理器宏,您可以在其上实现复杂的算法。

请注意,在C11(读取其标准n1570和某些C参考站点 )中,可以不同地处理不同类型(请参阅其§6.5.2)。

特别是,实现可以不同地处理intdouble和pointer值(它们的大小和对齐通常不同,请参见sizeofalignof ),并且一些ABI约定决定它们在不同的寄存器中传递(例如在函数调用中)。

所以你不能写一些处理(移植)所有intdouble等的东西……同样的方法(除非你有可变函数;用

您可能决定实现一些“通用”列表,其内容是一些任意指针。 但是你需要一些关于它们的约定 (谁分配指针,谁释放它,也许是允许的操作等等)。 查看Glib双链表以获取灵感。

在给定内容的类型名称的情况下,您还可以使用预处理器技术生成(列表中的) 抽象数据类型和实现它的函数。 深入了解SGLIB的灵感。

您还可以使用一些元编程技术:您将以某种方式描述元素的类型,并将该描述提供给元编程,这是一些C代码生成器。 深入了解SWIG的灵感。 生成的C代码将实现列表的抽象数据类型。

不要忘记内存管理问题 ,并清楚地描述和记录您的约定。 了解RAII 。

还要考虑复杂的情况,例如一些字符串列表(可能是动态分配的字符串或使用asprintf获得)。 你会发现事情并不简单,你需要明确的约定(例如,两个子列表之间是否可以共享一些字符串?该字符串何时是free -d,…)。

这可能是使用联盟的好地方。

您可以将基本数据类型定义为要支持的最常见类型的并集。 然后,您将定义所讨论类型的枚举,以使用该值来标记union包含的内容。

 enum element_type { TYPE_INT, TYPE_DOUBLE }; typedef union { int e_int; double e_double; } list_element; struct list_node { enum element_type type; list_element value; struct list_node* next; }; 

然后你像这样添加到列表:

 list list_cons(list_element d, enum element_type type, list l){ list m = malloc(sizeof(list_node)); m->type = type; m->value = element_copy(d); m->next = l; return m; }