3

私はプレーンC(組み込みプロジェクト、メモリが少ない)で作業しており、構造があります

typedef struct 
{
   int x;
   int y;
   int z;
   float angle;
   float angle1;
   float angle2;
} Kind1;

すべてのフィールドが必要な場合と、x、y、および角度のみが必要な場合があります。

C ++では、これらの3つのフィールドを持つ基本クラスを作成し、そこから追加の3つのフィールドを持つ別のクラスを継承し、必要に応じて1つまたは別のクラスをインスタンス化します。プレーンCでこの動作をエミュレートするにはどうすればよいですか?

私は私が次のようなものを作ることができることを知っています

typedef struct 
{
   int x;
   int y;
   float angle;
} Kind1;

typedef struct
{ 
   Kind1 basedata;
   int z;
   float angle2;
   float angle3;
}  Kind2;

しかし、Kind1へのポインターが要求されているKind2へのポインターを渡すことができません。

ポインタを型キャストしてオフセットすることが可能であることは知っていますが、もっと良い、より安全な方法があるのではないかと思います。

4

6 に答える 6

5

ポインタを型キャストしてオフセットすることが可能であることを私は知っています

必ずしも:

void foo(Kind1*);
struct Kind2
{ 
   Kind1 basedata;
   int z;
   float angle2;
   float angle3;
}

//...
Kind2 k;
foo(&(k.basedata));
于 2012-06-04T08:40:18.540 に答える
2

C++の場合と同じように実行できます。

struct Kind1
{
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   int z;
   float angle2;
   float angle3;
}

struct Kind
{
    Kind1 k1;
    Kind2 k2;
}
于 2012-06-04T08:38:40.633 に答える
2

プレーンCでは不可能です。言語にはそのような機能はありません。ただし、プリプロセッサマクロを使用して、タイプキャストとオフセットを単純化することができます。

于 2012-06-04T08:42:49.463 に答える
2

以下の例では、これらの定義を前提としています。

struct base { char c; } *a_base;
struct sub  { struct base b; int i; } *a_sub;

あなたの「例」は、実際には(最も単純な)適切な解決策です。

しかし、Kind1へのポインターが要求されているKind2へのポインターを渡すことができません。

はい、できます。以下はC11標準からのものですが、以前のリビジョンには同じ保証がありました[要出典]。

n1570 6.7.1.1.15

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

したがって(struct base*)a_sub == &a_sub->b((struct base*)a_sub)->c == a_sub->b.c

「スーパー構造体」が「サブ構造体」の最初のメンバーである限り、参照によってアクセスするときに一方を他方として扱うことができます。基本的にこれをしないでください。

void copy(struct base *from, struct base *to)
{
    *to = *from; // Oops, you just lost half your object.
}
于 2014-03-16T18:45:48.787 に答える
0

メモリが限られている場合は、2つの異なる構造体を宣言して健全性を維持します。

struct Kind1
{
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   int x;
   int y;
   int z;
   float angle;
   float angle2;
   float angle3;
}

はかつて#define、コードをより読みやすくするために、ユニオンとプリプロセッサを使用するコードを処理する必要がありました。しかし、これはすぐに狂気につながります。2つの構造が実際にサブクラスとして処理される場合、フィールドの再配置は最も悪ではありません。

struct Kind1
{
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   int x;
   int y;
   float angle;
   // extended data:
   int z;
   float angle2;
   float angle3;
}

それらが鋳造で注意深く使用される限り。ただし、問題が発生した場合は、すべてが正しく行われていることを証明するために、デバッグバージョンの名前チェックを行う必要があります。

struct Kind1
{
   char variant[6];  // initialized to "kind1" 
   int x;
   int y;
   float angle;
}

struct Kind2
{ 
   char variant[6];  // initialized to "kind2" 
   int x;
   int y;
   float angle;
   // extended data:
   int z;
   float angle2;
   float angle3;
}

function_expecting_kind2 (struct kind2 *p)
{
     if (strcmp (p->variant, "kind2"))
           error ("function expecting kind2 got '%s' instead", p->variant);
     ...
}
于 2012-06-04T09:23:48.500 に答える
0

私が考えることができる1つの方法は、2 * sizeof(float)バイト以下を節約します。

struct Kind2
{ 
   int z;
   float angle2;
   float angle3;
}

struct Kind1
{
   int x;
   int y;
   float angle;
   struct Kind2 *k2;
}

ここでは、全体の節約は、ポインタが消費するメモリの量に基づいています。

必要な場合にのみポインタを初期化します。

于 2012-06-04T09:42:53.240 に答える