0

I have two functions that do the exact same thing but in two different types of struct and this two types of struct are very similar.

Imagine I have this two structs.

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

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

Since my function to destroy each of the list is almost the same (Just the type of the arguments are different) I would like to make just one function to make the two thins.

I have this two functions

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

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

and this one:

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

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

Since they are very similar I thought making something like this:

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;
}

As you may now this is not working but I want to know if this is possible to achieve.

I must maintain both of the structs as they are.

4

4 に答える 4

2

@Dancrumbが指摘しているように、ここにはいくつかの設計上の問題があり、あなたがやろうとしていることを行うことはお勧めしません。

とは言うものの、キャストは実行可能であり、提供され、nodeOne常に同じになります(プロダクションコードでは決して依存しないものです)。nodeTwo

1つを選択するだけで、いつでもそれにキャストできます(shudder)。それらは異なる名前の同じ構造であるため、キャストは機能します。

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について話しているときは、destroy関数を別々のリストタイプに分けておくのは間違いありません。可能な限りカットアンドペーストコードを避けるようにしていますが、この場合、安全性、明快さ、保守性が優先されると思います。もちろん、私の意見です。あなたのマイレージは異なる場合があります :)

于 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は同一なので、なぜ2つの異なるタイプがあるのですか?

私が行方不明になっている何らかの理由がある場合、私はこれを拡張します:

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 に答える