質問
ヒューズを使用した標準イメージを含むディスク イメージがあります。スーパーブロックには以下が含まれており、次の生データを返す関数 read_superblock(*buf) があります。
Bytes 0-3: Magic Number (0xC0000112)
4-7: Block Size (1024)
8-11: Total file system size (in blocks)
12-15: FAT length (in blocks)
16-19: Root Directory (block number)
20-1023: NOT USED
私は C の初心者で、このプロジェクトを始めるにあたって、これを構造体またはいくつかの変数に読み込み、デバッグ用に printf を使用して単純に画面に出力する簡単な方法に興味があります。
最初は生データが見られると思って次のようなことをしようと考えていましたが、そうではないと思います。また、構造がなく、それを文字列として読み取ろうとしていますが、これもひどく間違っているようです。データを取得するためです。構造を指定し、各変数のバイト数を定義する方法はありますか?
char *buf;
read_superblock(*buf);
printf("%s", buf);
解決
はい、私はあなたが構造にこれを読んでたほうが良いと思います。有用なデータを含むフィールドは、すべての32ビット整数である、あなたは(標準ヘッダファイルstdint.h
で定義されたタイプを使用して)次のように見える構造を定義することができます:
typedef struct SuperBlock_Struct {
uint32_t magic_number;
uint32_t block_size;
uint32_t fs_size;
uint32_t fat_length;
uint32_t root_dir;
} SuperBlock_t;
char*
を呼び出すときにあなたはこのように、read_superblock
に構造をキャストすることができます:
SuperBlock_t sb;
read_superblock((char*) &sb);
さて、あなたのデータをプリントアウトするには、次のように電話をかけることができます:
printf("%d %d %d %d\n",
sb.magic_number,
sb.block_size,
sb.fs_size,
sb.fat_length,
sb.root_dir);
あなたは(つまり、あなたがあなたのデータを読み込む際にバイトをスワップする必要があるかもしれません)整数データを読んでいることから、このような技術を使用している場合、ご使用のプラットフォームのエンディアンを意識する必要があることに注意してください。あなたが最初のフィールドにマジックナンバーを使用してすぐにそれを決定することができる必要があります。
それはそれをキャストすることなく、このような構造を渡すために、通常は望ましいということに注意してください。これは、あなたが、コンパイラの型チェックを利用することを可能にし、キャスティングが隠れることが潜在的な問題を解消します。しかし、それは、直接構造にデータを読み取るためにread_superblock
の実装を変更することになってしまいます。これは難しいことではないと(あなたの質問にほのめかしとして、あなたのデータがファイルであると仮定すると)そうのように、標準のCランタイム関数fread
を使用して行うことができます:
fread(&sb.magic_number, sizeof(sb.magic_number), 1, fp);
fread(&sb.block_size, sizeof(sb.block_size), 1, fp);
...
他のヒント
ここに 2 つのことを追加します。
- 生データを構造体に取り込むときは、構造体全体が 32 ビット符号なし整数で構成されている場合でも、構造体にゼロ パディングを設定することをお勧めします。gcc ではこれを実行します
#pragma pack(0)
構造体定義の前と#pragma pack()
その後。 - 潜在的なエンディアンの問題に対処するには、次の 2 つの呼び出しに注目してください。
ntohs()
そしてntohl()
, 、それぞれ 16 ビット値と 32 ビット値の場合。これらはネットワークのバイトオーダーからホストのバイトオーダーに切り替わることに注意してください。これらが同じである場合 (x86 ベースのプラットフォームではない場合)、何も行いません。ホストからネットワークのバイトオーダーに移動するには、次のようにします。htons()
そしてhtonl()
. 。ただし、このデータはネットワークではなくファイルシステムから取得されているため、エンディアンが問題かどうかはわかりません。期待する値を比較することで簡単に理解できるはずです (例:ブロック サイズ) を取得した値 (16 進数) に置き換えます。
それはあなたが成功しEmerickが提案された構造にデータをコピーした後にデータを印刷することは難しいことではありません。あなたはデータを保持するために使用する構造体のインスタンスはSuperBlock_t_Instanceを命名されているとします。
次に、あなたはこのようにそのフィールドを印刷することができます:
printf("Magic Number:\t%u\nBlock Size:\t%u\n etc",
SuperBlock_t_Instance.magic_number,
SuperBlock_t_Instance.block_size);