1

バイナリファイルを読み書きするプログラムがあります。ファイルは同じプラットフォームでのプログラムの実行間で交換可能ですが、あるマシンで作成されたファイルは、タイプのサイズ、エンディアンなどにより、別のプラットフォームでは有効でない場合があります。

特定のファイルが特定のアーキテクチャでの読み取りに有効であると断言できるようにするための簡単な方法が必要です。私はファイルのクロスアーキテクチャを作成することに興味がありません(実際、ファイルはメモリマップト構造体です)。ファイルを読み取る前に、ファイルが同じサイズタイプなどのアーキテクチャで作成されていることを確認する方法だけが必要です。

1つのアイデアは、ファイルの先頭に一定のマジックナンバーを持つ構造体を書き込むことです。これを読み取って確認することができます。sizeofもう1つは、さまざまなタイプを1バイト整数で格納することです。

これはCの場合ですが、同じ種類の問題がある言語の場合、問題は言語に依存しないと思います。

これを行うための最良の方法は何ですか?

この質問のタイトルの修正を歓迎します!

4

4 に答える 4

2

ファイルのアイデアの冒頭にあるマジックナンバーが好きです。あなたは魔法の値でこれらのチェックをすることができます:

  • 少なくとも2つのマジックバイトがあり、それらを単一のマルチバイト整数として扱う場合、エンディアンの変化を検出できます。たとえば、0xABCDを選択し、コードが0xCDABを読み取る場合、ファイルが書き込まれたプラットフォームとは異なるエンディアンのプラットフォームを使用しています。

  • 4バイトまたは8バイトの整数を使用する場合、データ型を選択して2つのプラットフォームでサイズが異なる場合は、32ビットと64ビットのプラットフォームを検出できます。

  • 整数以上のものがある場合、または慎重に選択した場合は、別のプログラムによって書き出されたファイルを誤って読み取る可能性を高い確率で除外できます。避けるべき値の適切なリストについては、Unixy型システムの/ etc/magicを参照してください。

于 2010-08-23T17:03:09.610 に答える
1
#include <stdint.h>

union header {
     uint8_t a[8];
     uint64_t u;
};

const struct header h = { .u = (sizeof(      short  ) <<  0 )
                             | (sizeof(        int  ) <<  8 ) 
                             | (sizeof(       long  ) << 16 ) 
                             | (sizeof(   long long ) << 24 )
                             | (sizeof(       float ) << 32 )
                             | (sizeof(      double ) << 40 )
                             | (sizeof( long double ) << 48 )
                             | 0 } ;

これは、浮動小数点数が非常に難しいことを除いて、型のサイズとエンディアンを検証するのに十分なはずです。

浮動小数点数がライターとリーダーで同じ形式で格納されていることを確認する場合は、2つの定数浮動小数点数(0、1、および-1よりも興味深い)を異なる形式で格納することをお勧めします。このヘッダーの後にサイズを設定し、それらが本来あるべきものであることを確認します。

バージョン番号とともに実際のマジックストリングを保存することも、これが正しいファイル形式であることを確認するための別のチェックとして役立つ可能性が非常に高くなります。

フロートなどを気にしない場合は、自由に削除してください。常に1バイトであると想定されているため、charは含めませんでした。

次のような構造体のsizeも保存することをお勧めします。

struct misalligned {
    char c;
    uint64_t u;
};

これにより、ファイルを生成したコードを生成したコンパイラーの配置とパディングを簡単に判別できるようになります。これがアライメントを気にするほとんどの32ビットコンピュータで行われた場合、cとuの間に3バイトのパディングがあるため、サイズは96になりますが、64ビットマシンで行われた場合、サイズは128になり、次のようになります。 cとuの間の7バイトのパディング。これがAVRで行われた場合、パディングがないため、これのサイズはおそらく9になります。

ノート

  • この回答は、ファイルがメモリマップされており、ファイルの形式が間違っていることを認識する以外に移植性は必要ないという質問に依存していました。質問が一般的なファイルの保存と検索に関するものだったとしたら、私は違った答えをしたでしょう。最大の違いは、データ構造のパッキングです。
于 2010-08-23T22:08:48.900 に答える
1

uname(2)関数(または非POSIXプラットフォームでは同等のもの)を呼び出し、ファイルの先頭にあるヘッダーにsysnamemachineフィールドを書き込みます。struct utsname

(サイズとエンディアンだけでなく、浮動小数点形式と構造パディング標準も異なります。したがって、主張したいのは実際にはマシンABIと同じです)。

于 2010-08-24T01:25:06.960 に答える
0

まず、ウォーレン・ヤングが提供した以前の回答に完全に同意します。

これは、私たちが話しているメタデータのケースです。

ファイルシステムと同種のコンテンツでは、バイナリファイルの先頭に(構造のサイズに合わせて)メタデータを1つパディングすることをお勧めします。これにより、データ構造のアライメントを維持し、追加書き込みを簡素化できます。

異種の場合は、各データまたはデータ範囲の前にStructure-ValueまたはStructure-Length-Value(Type Length Valueとも呼ばれます)を使用することをお勧めします。

ランダムに結合されたストリームでは、HDLC(Wikipedia)などの構造と同期させたり、バイナリデータの一定の流れの中でメタデータを繰り返したりすることができます。オーディオ/ビデオ形式に精通している場合は、本質的にフレームで構成されているデータフロー内のタグについて考えることができます。

いいテーマ!

于 2010-08-23T22:22:13.527 に答える