0

Cについて質問があり、構造体のメンバーにアクセスする場合にのみ、部分的なタイプの「継承」をモックしようとしています。次の例を見てください。

#pragma pack(push,1)
typedef struct foo
{
    int value;
    int value2;
}foo;
typedef struct foo_extended
{
    // "inherits" foo
    int value;
    int value2;
    // "inherits" foo stops
    //we also have some additional data
    float additional;
}foo_extended;
#pragma pack(pop)


//! This function works for both foo types
void workboth(void* objP)
{
    foo* obj = (foo*)objP;

    obj->value = 5;
    obj->value2 = 15;
}

//! This works only for the extended
void workextended(foo_extended* obj)
{
    obj->value = 25;
    obj->value2 = 35;
    obj->additional = 3.14;
}

int main()
{
    foo a;
    foo_extended b;

    workboth(&a);
    workboth(&b);
    workextended(&b);

    return 0;
}

これは私のシステムでは機能しますが、関連する構造が正しくパッキングされている限り (コンパイラによっては)、これを移植できるかどうかという質問があります。他のコンパイラでもタイトなパッキングを正しく呼び出す #ifndefs が必要になると思います。

もちろん、明らかな問題は、型チェックが完全に欠如していて、正しい使用法の責任をすべてプログラマーに負わせていることですが、これが移植可能かどうかは疑問です。ありがとう!

PS: 私が準拠しようとしている標準は C99 であることを忘れていました。

4

3 に答える 3

1

私は少し違う方法をとっています。同じ値を使用する代わりに、構造体に構造体を作成します。この方法では、パッキングは不要です。

typedef struct foo
{
    int value;
    int value2;
}foo;

typedef struct foo_extended
{
    foo father;
    float additional;
}foo_extended;

残りはほとんどあなたが示したとおりですが、わずかな違いがあります。

void workextended(foo_extended* obj)
{
    obj->father.value = 25;
    obj->father.value2 = 35;
    obj->additional = 3.14;
}

しかし、階層内の最初のオブジェクトのフィールドとして id を追加して、キャストが正しいオブジェクトに確実に行われるようにします。

このメソッドは、C 標準で動作することが保証されています。

于 2012-04-29T09:32:10.973 に答える
1

structC11 の時点で、古い標準の拡張機能として一部の既存のコンパイラでもサポートされているため、そのために匿名を使用する必要があります。

struct foo_extended {
    struct {
      int value;
      int value2;
    };
    //we also have some additional data
    float additional;
};

これにより、サブ構造は、特にその部分の配置に関係するものとまったく同じレイアウトにfooなります。まったく同じフィールドを同じ順序で持つ異なるコンパイル単位間で互換性を保つにstructは、同じようにレイアウトする必要があります。

(パックされたプラグマの影響は私にはあまり明確ではありません)

あなたのfoo構造は最初のものであるため、foo_extended常にその構造内のオフセットにある必要があります0

于 2012-04-29T09:57:51.497 に答える
0

C99 ドラフトの 6.7.2.1/12 と /13 を読むと、同じ初期メンバーを持つ 2 つの異なる構造体は、最初の異なるメンバーまで互換性があると見なすことができると思います。

6.7.2.1/12

構造体または共用体オブジェクトの各非ビット フィールド メンバーは、その型に適した実装定義の方法で整列されます。

6.7.2.1/13

構造体オブジェクト内で、非ビット フィールド メンバーとビット フィールドが存在するユニットには、宣言された順序で増加するアドレスがあります。適切に変換された構造体オブジェクトへのポインターは、その最初のメンバー (または、そのメンバーがビットフィールドの場合は、それが存在するユニット) を指し、その逆も同様です。構造体オブジェクト内に名前のないパディングがある場合がありますが、先頭にはありません。

于 2012-04-29T09:55:47.317 に答える