2

フィールド/メンバーへのマッピングが実行時にのみ認識される(複雑な)逆シリアル化を実装しようとしています。とにかく私がやろうとしていることは次のようなものです:

Class A
{
  public:
    int a;    // index 0
    float b;  // index 1
    char c;   // index 2
} 

次に、2つの配列があります。1つはフィールドのインデックスを持ち、もう1つはタイプを示すものを持っています。次に、配列を反復処理して、バイトストリームからフィールドに書き込みます。

説明がお粗末で申し訳ありませんが、コードで実装する方法がわかりません。どんなアイデアでもありがたいです!

4

4 に答える 4

1

必要な問題や決定はたくさんあります。最も単純な方法では、フィールドごとにオフセットを保持することができA、タイプをオンにして、フィールドへのポインターを介して設定することができます。たとえばint16_t、入力ストリームにエンコーディングフィールド番号があると仮定し、使用static_cast<>するのが少し良い場所などを使用する努力をせず、0フィールド番号の入力ターミネータを仮定します...

A a;
char* pa = (char*)&a;
char* p_v = (char*)&input_buffer;

...
while ((field_num = *(int16_t)p_v) && (p_v += sizeof(int16_t)))
    switch (type[field_num])
    {
      case Int32:
        *(int32_t*)(p_a + offset[field_num]) = *(int32_t*)(p_v);
        p_v += sizeof(int32_t);
        break;
      ...
    }

ntohl()エンディアン変換を処理するために、egなどを使用することを検討することをお勧めします。

于 2013-01-24T06:02:59.343 に答える
1

実行時にインデックスを指定してフィールドアドレスを指定できる言語構造は考えられません。「タイプ」配列に実際にフィールドサイズを含めることができれば、次のようなことができたでしょう:

istream &in = <get it somehow>;
size_t *field_size = <get it somehow>;
size_t num_of_fields = <get it somehow>;
A a;

char *ptr = reinterpret_cast<char *>(&a);
for (int i = 0; i < num_of_fields; i++)
{
    in.read(ptr, field_size[i]);
    ptr += field_size[i];
}

これは、クラスが単純で、仮想関数メンバーを持たない (またはそのようなクラスから継承する) 場合に当てはまることに注意してください。その場合は、クラス内でフィールドが始まるバイト オフセットを取得するためのダミー メンバーを含めることをお勧めします。

class A
{
    int __dummy;   /* must be the first data member in the class */

    ...
    <rest of your class definition here>
};

次に、 ptrの初期化を次のように変更します。

ptr = reinterpret_cast<char *>(&a) + offsetof(A, __dummy);

このコードのもう 1 つの暗黙の前提は、このコードを実行するマシンとシリアル化されたデータを受信するマシンの両方で、マシンのバイト順が同じであるということです。そうでない場合は、ストリームから読み取ったデータのバイト順を変換する必要があります。もちろん、この変換は型に依存しますが、フィールドごとに別の変換関数の配列を持つことができます。

于 2013-01-24T06:11:40.400 に答える
1

はい、できます。ただし、実行する際に注意する必要があることが 2 つあります。

すべてのコンパイラは、オブジェクトの先頭に実際には関係のないものを追加する(const char*)&A.aため (たとえば、visualc はそこに vtable を配置します)、自分が思っていることを書き始めることはありません。オブジェクトのアドレスから開始します。

次に#pragma pack(1)、ディスクに書き込む必要があるクラスを宣言する前に a を実行することをお勧めします。コンパイラは通常、DMA 転送をより効率的にするためにクラス メンバーを調整するため、これにも問題が発生する可能性があるからです。

動的な部分では、必要なフィールドの組み合わせごとに 1 つのクラス定義を作成することが許容される場合は、このようにしても問題ありません。それ以外の場合は、クラスにハッシュ テーブルを含めてシリアライズ/デシリアライズする方がよいでしょう。キーと値のペアをファイルに書き込むことにより、そのコンテンツ

于 2013-01-24T06:19:39.293 に答える
-1

コンパイラに任せてください:

関数を記述しoperator>>ます。

于 2013-01-24T05:44:41.970 に答える