1

構造体は、データのバイナリ ブロブ (つまり、ファイルまたはネットワーク パケット) を解析するための便利な方法のようです。これは、ブロブに可変サイズの配列があるまでは問題ありません。例えば:

struct nodeheader{
        int flags;
        int data_size;
        char data[];
};

これにより、最後のデータ文字を見つけることができます。

nodeheader b;
cout << b.data[b.data_size-1];

問題は、複数の可変長配列が必要なことです:

struct nodeheader{
    int friend_size;
    int data_size;
    char data[];
    char friend[];
};

これらの構造を手動で割り当てているわけではありません。次のようなファイルがあります。

char file_data[1024];
nodeheader* node = &(file_data[10]);

バイナリファイル(より具体的にはクラスファイル)を解析しようとしています。私はJavaで実装を書きました(これは私のクラスの割り当てでした)、いいえ、私はC++で個人的なバージョンをやっていて、100行のコードを書かなくても済むことを望んでいました. 何か案は?

ありがとう、ステファン

4

6 に答える 6

3

複数の可変サイズの配列を持つことはできません。コンパイラはコンパイル時にfriend[]がどこにあるかをどのように知る必要がありますか? フレンドの場所は data[] のサイズに依存し、データのサイズはコンパイル時に不明です。

于 2008-10-07T15:02:57.863 に答える
3

これは非常に危険な構造です。構造体に可変長配列を含めることができるのは、構造体が LAST 要素である場合のみです。その場合、十分なメモリを割り当てる必要があります。次に例を示します。

nodeheader *nh = (nodeheader *)malloc(sizeof(nodeheader) + max_data_size);

あなたがしたいことは、通常の動的に割り当てられた配列を使用することです:

struct nodeheader
{
  char *data;
  size_t data_size;
  char *friend;
  size_t friend_size;
};

nodeheader AllocNodeHeader(size_t data_size, size_t friend_size)
{
  nodeheader nh;
  nh.data = (char *)malloc(data_size);  // check for NULL return
  nh.data_size = data_size;
  nh.friend = (char *)malloc(friend_size);  // check for NULL return
  nh.friend_size = friend_size;

  return nh;
}

void FreeNodeHeader(nodeheader *nh)
{
  free(nh->data);
  nh->data = NULL;
  free(nh->friend);
  nh->friend = NULL;
}
于 2008-10-07T15:06:49.697 に答える
1

できません-少なくとも、あなたが試みている単純な方法ではできません. 構造体の末尾にあるサイズのない配列は、基本的に構造体の末尾へのオフセットであり、末尾を見つける組み込みの方法はありません。

すべてのフィールドはコンパイル時に数値オフセットに変換されるため、その時点で計算可能である必要があります。

于 2008-10-07T15:05:17.983 に答える
1

これまでの答えは、単純な問題を非常に複雑にしています。Meckiは、あなたがやろうとしている方法でそれを行うことができない理由について正しいですが、非常によく似た方法で行うことができます:

struct nodeheader
{
    int friend_size;
    int data_size;
};

struct nodefile
{
    nodeheader *header;
    char *data;
    char *friend;
};

char file_data[1024];

// .. file in file_data ..

nodefile file;
file.header = (nodeheader *)&file_data[0];
file.data = (char *)&file.header[1];
file.friend = &file.data[file->header.data_size];
于 2008-10-09T07:31:13.280 に答える
0

あなたがしていることには、フォーマットのエンコーダー/デコーダーが必要です。デコーダーは生データを取得して構造を埋め (この場合、データの各セクションのコピーにスペースを割り当てます)、デコーダーは生のバイナリを書き込みます。

于 2008-10-07T15:21:40.807 に答える
-1

('Use std::vector' でした)

編集:

フィードバックを読んで、答えを拡大する必要があると思います。次のように、2 つの可変長配列を構造体に効果的に適合させることができます。また、file_data がスコープ外になると、ストレージが自動的に解放されます。

struct nodeheader {
    std::vector<unsigned char> data;
    std::vector<unsigned char> friend_buf; // 'friend' is a keyword!
    // etc...
};

nodeheader file_data;

これで、file_data.data.size() などで長さが得られ、必要に応じて &file_data.data[0] でデータへの生のポインターが得られます。

ファイルからファイルデータを少しずつ埋める必要があります-各バッファの長さを読み取り、宛先ベクトルで resize() を呼び出してから、データを読み取ります。(これをもう少し効率的に行う方法があります。ディスク ファイル I/O のコンテキストでは、それは問題ではないと想定しています)。

ちなみに、OP の手法は、たとえば最後に VLA が 1 つしかないなど、彼の「素晴らしくてダンディな」場合でも正しくありません。

char file_data[1024];
nodeheader* node = &(file_data[10]);

file_data が nodeheader タイプに対して適切に配置されているという保証はありません。malloc() で file_data を取得することをお勧めします。これにより、任意の型にアラインされたポインターを返すことが保証されます。そうでない場合は (より良い)、最初にバッファーが正しい型であることを宣言します。

struct biggestnodeheader {
    int flags;
    int data_size;
    char data[ENOUGH_SPACE_FOR_LARGEST_HEADER_I_EVER_NEED];
};

biggestnodeheader file_data;
// etc...
于 2008-10-07T15:08:40.800 に答える