質問
構造体は、データのバイナリBLOB(ファイルまたはネットワークパケット)を解析する便利な方法のようです。これは、BLOBに可変サイズの配列を作成するまでは問題ありません。例えば:
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行のコードを書かなくても逃げることを望んでいました。アイデアはありますか?
ありがとう、 ステファン
解決
複数の可変サイズの配列を持つことはできません。コンパイル時にコンパイラはfriend []の場所をどのように知る必要がありますか?友人の場所はdata []のサイズに依存し、データのサイズはコンパイル時に不明です。
他のヒント
これは非常に危険な構造であり、これに反対することをお勧めします。構造体に可変長配列を含めることができるのは、それが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;
}
できません-少なくともあなたが試みている簡単な方法ではありません。構造の最後にあるサイズのない配列は、基本的に構造の最後へのオフセットであり、最後を見つけるための組み込みの方法はありません。
すべてのフィールドはコンパイル時に数値オフセットに変換されるため、その時点で計算可能である必要があります。
これまでの答えは、単純な問題を非常に複雑にしています。 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];
あなたがしていることのために、あなたはフォーマットのためにエンコーダー/デコーダーを必要とします。デコーダーは生データを取得し、構造にデータを入力し(この場合、データの各セクションのコピーにスペースを割り当てます)、デコーダーは生のバイナリを書き込みます。
(「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()などが長さを提供し、&amp; 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を取得することをお勧めします。malloc()は、あらゆるタイプにアラインされたポインターを返すことを保証します。
struct biggestnodeheader {
int flags;
int data_size;
char data[ENOUGH_SPACE_FOR_LARGEST_HEADER_I_EVER_NEED];
};
biggestnodeheader file_data;
// etc...