gpt4 book ai didi

c - ANSI C 中的通用容器

转载 作者:行者123 更新时间:2023-11-30 20:07:34 25 4
gpt4 key购买 nike

出于对这个问题并不重要的几个原因,是否可以为 ANSI 中的通用结构实现一个列表(一个容器)?同一个列表可以包含不同类型的结构吗?

编辑:经过几次建议,我正在考虑一些选项。但我仍然不清楚为什么没有标准方法来做到这一点。 ANSI C 中不需要吗?唯一的方法是使用另一种语言?

干杯

最佳答案

取决于您想做什么,这是可能的。这是一个令人头疼的问题,但这是可能的。

您可以使用void指针来创建通用列表,例如

struct glist {
void *data;
stuct glist *next;
};

data 成员可以指向任何类型的对象。问题是,一旦分配了指针,您就会丢失该类型信息;您需要单独跟踪类型。您可以使用整数或枚举值来标记类型,例如

enum dtype {type_A, type_B, type_C, ...};

struct glist {
void *data;
enum dtype data_type;
struct glist *next;
};

#define TYPE_A 1
#define TYPE_B 2
...
struct glist {
void *data;
int data_type;
struct glist *next;
};

当您从列表中检索元素时,您需要检查 data_type 成员,以确定根据数据类型调用哪些函数或执行哪些过程:

switch (elem->data_type)
{
case TYPE_A: // process for TYPE A
break;

case TYPE_B: // process for TYPE B
break;

...
}

或者,您可以存储指向一个或多个对特定数据类型进行操作的函数的指针,并完全跳过 switch 或 if-else 语句:

struct glist {
void *data;
void (*process)(const void *);
void (*copy)(const void *);
void (*delete)(const void *); // not shown
struct glist *next;
};

对于每种数据类型,您创建一个流程函数的实例,并将指向该函数的指针与节点绑定(bind)。该函数必须采用 void * 作为输入,但它将转换为适当的类型以进行处理:

void process_typeA (const void *data)
{
typeA *obj = (typeA *) data; // cast away const
// process obj as necessary
}

void *copy_typeA (const void *data)
{
typeA *obj = (typeA *) data;
typeA *newObj = malloc(sizeof *newObj);
if (newObj)
// copy from obj to newObj
return newObj;
}

void addItem (struct glist *list, const void *obj,
void (*process)(const void *),
void *(*copy)(consg void *),
void (*delete)(const void *))
{
struct glist *newNode = malloc(sizeof *newNode);
newNode->copy = copy;
newNode->delete = delete;
newNode->process = process;
newNode->data = (*copy)(obj);
newNode->next = NULL;

// add newNode to list
}

void foo(void)
{
struct glist *myList = new_list(); // not shown here
...
addItem(myList, myTypeAObj, process_typeA, copy_typeA, delete_typeA);
addItem(myList, myTypeBObj, process_typeB, copy_typeB, delete_typeB);
...
}

然后,当您浏览列表时,您可以调用适合该特定节点的process函数:

void processList(struct glist *list)
{
struct glist *node = list;
while (node)
{
node->process(node->data);
node = node->next;
}
...
}

此方法的优点在于您将该节点的行为与该节点本身相关联;您不需要不断向 switch 或 if-else 链添加 case。缺点是你要处理大量的指针,你必须为你想要使用的每种数据类型实现一个单独的处理/复制/删除函数,你正在做非-少量的内存管理(您需要复制和删除方法,一旦您考虑一下,原因就显而易见),并且您将任何类型安全的概念扔到了窗外并进入迎面而来的交通中;您将失去任何编译器级别的保护,以防止将错误的处理/复制/删除函数与错误的数据类型相关联。

关于c - ANSI C 中的通用容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11658264/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com