0

我有两个功能完全相同,但在两种不同类型的结构中,这两种类型的结构非常相似。

想象一下我有这两个结构。

typedef struct nodeOne{
    Date *date;
    struct nodeOne *next;
    struct nodeOne *prev;
}NodeOne;

typedef struct nodeTwo{
    Date *date;
    struct nodeTwo *next;
    struct nodeTwo *prev;
}NodeTwo;

由于我销毁每个列表的函数几乎相同(只是参数的类型不同),我只想制作一个函数来使两个变薄。

我有这两个功能

void destroyListOne(NodeOne **head, NodeOne **tail){
    NodeOne *aux;

    while (*head != NULL){
        aux = *head;
        *head = (*head)->next;
        free(aux);
    }
    *tail = NULL;
}

和这个:

void destroyListTwo(NodeTwo **head, NodeTwo **tail){
    NodeTwo *aux;

    while (*head != NULL){
        aux = *head;
        *head = (*head)->next;
        free(aux);
    }
    *tail = NULL;
}

由于它们非常相似,我想制作这样的东西:

void destroyList(void **ini, void **end, int listType){

    if (listType == 0) {
        NodeOne *aux;
        NodeOne head = (NodeOne) ini;
        NodeOne tail = (NodeOne) ed;

    }
    else {
        NodeTwo *aux;
        NodeTwo head = (NodeTwo) ini;
        NodeTwo tail = (NodeTwo) ed;
    }

    while (*head != NULL){
        aux = *head;
        *head = (*head)->next;
        free(aux);
    }
    *tail = NULL;
}

正如您现在可能无法正常工作,但我想知道这是否可以实现。

我必须保持这两个结构原样。

4

4 回答 4

2

正如@Dancrumb 所指出的,这里有一些设计问题,我不建议你做你想做的事情。

也就是说,铸造可以完成,提供nodeOne并且nodeTwo总是相同的(我在生产代码中永远不会依赖这一点)。

你可以只选择一个,然后总是投给它(颤抖)。由于它们是具有不同名称的相同结构,因此演员表有效:

void destroyList(void *ini, void *end, int listType){

    NodeOne *aux = NULL;
    NodeOne **head = ini;
    NodeOne **tail = end;

    while (*head != NULL){
        aux = *head;
        *head = (*head)->next;
        free(aux);
    }
    *tail = NULL;
}

另请注意,在 C 中,您不需要显式强制转换,因为 void * 可以在没有强制转换的情况下隐式转换为任何其他指针类型。

但说真的,请不要这样做。它是脆弱的、不可维护的和容易出错的。


看了@Torp 的回答后,我想详细说明一下问题的精神和我的回答。通过对@Torp 代码的错误修复(它无法编译并且存在几个指针问题),它可以工作。也就是说,我仍然认为你不应该让它工作。

特别是当我们谈论 C(而不是 C++)时,我肯定会将销毁函数分开用于单独的列表类型。我尽量避免剪切和粘贴代码,但在这种情况下,我认为安全性、清晰性和可维护性会胜出。我的意见,当然。你的旅费可能会改变 :)

于 2012-06-06T16:37:33.480 回答
2

尽管我不想这么说,这就是模板是在 C++ 中发明的原因。你确定不能用吗?

像这样的东西应该工作:

void destroyList(void **ini, void **end, int listType)
{
    void *aux;
    void *head = ini;
    void *tail = end;


    while (*head != NULL){
        if (listType == 0) {
           aux = (NodeOne *)*head;
           *head = ((NodeOne*)*head)->next;
           free((NodeOne*)aux;
        } else {
           ... same thing with casts to NodeTwo* ...
        }
    }
    *tail = NULL;
}

不确定我把所有的类型转换都放在哪里,但你明白了。

于 2012-06-06T16:38:51.500 回答
0

如果我设计这个,我会这样做:

typedef struct node{
    Date *date;
    struct node *next;
    struct node *prev;
} Node;

既然NodeOneNodeTwo是相同的,为什么会有两种不同的类型呢?

如果有某种原因我失踪了,那么我会扩展这个:

typedef struct nodeOne {
    Node nodeInfo;
    /* additional */
} NodeOne

typedef struct nodeTwo {
    Node nodeInfo;
    /* additional */
} NodeTwo

然后,只需将该nodeInfo字段传递给您的节点操作函数。

于 2012-06-06T16:22:49.440 回答
0

编写一个包含所有函数的#define,只需将函数名和结构类型作为参数。

#define DECLARE_DESTRUCTION_FUNCT(_name_, _type_) void _name_(_type_ **head, _type_ **tail){\
_type_ *aux;\
\
while (*head != NULL){\
    aux = *head;\
    *head = (*head)->next;\
    free(aux);\
}\
*tail = NULL;\
}

DECLARE_DESTRUCTION_FUNCT(destroyListOne, NodeOne)
DECLARE_DESTRUCTION_FUNCT(destroyListTwo, NodeTwo)

这种从 C++ 复制模板。带来编译时类型检查的好处。

于 2012-06-06T16:55:40.563 回答