0

私は以下のような機能を持っています。2 つの引数を取ります。1 つは構造体を指す void ポインターで、もう 1 つはバージョン番号です。渡されたバージョンに応じて、void ポインターを 2 つの構造にキャストする必要がありますが、これらはほとんど同じです (1 つは配列を持ち、もう 1 つはポインターを使用します)。

struct some_v0{
    char a;
    int some_array[200];
    char b;
}
struct some_v0{
    char a;
    int *some_array;
    char b;
}
void some_api(void * some_struct, int version){
    /* Depending on version the void pointer is cast to 2 different version of a struct*/
    /* This is followed by some common code which is similar for both version of struct(as array access and pointer access have similar code)*/
}

配列アクセスとポインタ アクセスのコードは似ているため、2 つのバージョンの唯一の違いは void ポインタのキャストです。

私の現在の方法は以下の通りです。

void some_api(void * some_struct, int version){


    if(version == 0){
        struct some_v0 v0;
        v0= *(struct some_v0 *)some_struct;
        /* block of code which uses v0 */
    }
    if(version == 1){
        struct some_v1 v1;
        v1= *(struct some_v1 *)some_struct;
        /* block of code which uses v1 */
    }
}

配列アクセスとポインター アクセスが類似しているため、上記のコード ブロックは類似しています。上記の場合、コードの重複を避けたい。どんな助けでも大歓迎です。コードの重複を避けるのに役立つソリューションを探しています。

注: 構造体メンバーが定義されている順序を変更することはできません。配列が構造体定義の最後の要素である場合、解決策は簡単であることを理解しています。下位互換性のため、構造体要素の順序を変更することはできません。

編集 1: 入力構造体を入力して呼び出し元の関数に返す必要がある類似の API がもう 1 つあります。

void some_api(void * some_struct, int version){


    if(version == 0){
        struct some_v0 *v0;
        v0= (struct some_v0 *)some_struct;
        /* block of code which uses v0  fill v0*/
    }
    if(version == 1){
        struct some_v1 *v1;
        v1= (struct some_v1 *)some_struct;
        /* block of code which uses v1. Fill v1 */
    }
}

このケースも処理でき、コードの重複を回避できるソリューションを探しています。

4

2 に答える 2

4

一般性の問題に関しては、v0 の配列と v1 のポインターのみの違いがあれば、実際に構造体を使用してsome_v1構造体にアクセスできます。some_v0

お気に入り

struct some_v1 v1;

if(version == 0){
    v1.a = ((struct some_v0 *) some_struct)->a;
    v1.some_array = ((struct some_v0 *) some_struct)->some_array;
    v1.b = ((struct some_v0 *) some_struct)->b;
} else if (version == 1)
    v1 = *(struct some_v1 *) some_struct;
}

この後、構造v1は両方のバージョンで使用できます。


some_v2メンバーのみを構造体に追加する構造体を後で追加する場合some_v1は、同じ手法を使用できます。v1 構造をコピーした後、v2 構造にフィールドを設定することを忘れないでください。

例えば

struct some_v2
{
    char a;
    int *some_array;
    char b;
    int c;  /* New field in v2 */
};

それからあなたはすることができます

struct some_v2 v2;

if(version == 0){
    v2.a = ((struct some_v0 *) some_struct)->a;
    v2.some_array = ((struct some_v0 *) some_struct)->some_array;
    v2.b = ((struct some_v0 *) some_struct)->b;
    v2.c = 0;
} else if (version == 1)
    memcpy(&v2, some_struct, sizeof(struct some_v1));
    v2.c = 0;
} else {
    v2 = *(struct some_v2 *) some_struct;
}

必要なときに簡単に再利用できるように、これらすべてを別の関数に入れることをお勧めします。


質問の更新後、ポインタを使用したい場合は、次のようなことができます(構造の2つのバージョンのみを持つオリジナルを考慮して):

struct some_v1 v1_np;  /* Non-pointer structure */
struct some_v1 *v1;  /* the pointer we will work with */

if (version == 0) {
    v1_np.a = ((struct some_v0 *) some_struct)->a;
    v1_np.some_array = ((struct some_v0 *) some_struct)->some_array;
    v1_np.b = ((struct some_v0 *) some_struct)->b;
    v1 = &v1_np;
} else if (version == 1) {
    v1 = (struct some_v1 *) some_struct;
}

ご覧のとおり、これは元のバージョンと非常によく似ています。ここでの問題は、v0 と v1 の構造がまったく互換性がないことです (sizeof両方の構造を調べてみると、理由がわかります)。そのv1_npため、ポイントできる一時的な構造が必要ですv1

于 2013-10-18T06:15:19.523 に答える
1

私がこの問題を解決した方法。

構造体の 2 つのバージョンを持つ代わりに、以下のように some_v0 に新しい構造体メンバーを導入しました。注: ここでは構造体メンバーの順序を変更していません。

struct some_v0{
    char a;
    int some_array[200];
    char b;
    int *some_array_v1;
};

API 関数は次のように実装できます。

void some_api(void * some_struct, int version){
    struct *some_v0 v0= (some_v0 *)ptr;
    int *ptr; /*pointer we will be working on*/
    if (version == 0) {
         ptr=some_v0->some_array;
    } else if (version == 1) {
         ptr=some_v0->some_array_v1;
    }
/*Common code block which uses ptr wherever some_arry is used. All other members can be dereferenced using v0*/
}

これにより、コードの重複が回避され、API バージョンも処理されます。これはまた、呼び出し元の関数がそれを使用できるように、構造体ポインターで値を返すことにも注意を払います。

于 2013-10-20T10:26:20.260 に答える