アライメントの話

初めに

 ネットワークストリームに対応させるためにエンコーダの実装を変更していたら1日潰れた(まぁファイルしか読み込ませていないのでデバッグ終わってないのだが)。予想より早く終わったぞ。その時、使い安いバイナリーリーダーがないので自作して公開してみた(Crates.ioに置いた方が管理が簡単なので)ポインタの管理が面倒になったのが大きいぞ。もっともポインタの管理をライブラリに任せるとデバッグが面倒なのだが。

 ヘッダの読み込みなどは、Cの場合構造体にそのまま流し込めば終わりなのに一々をコードを書かないと行けないのがつかれる。むしろ、そのライブラリでも作ろうかな。

アライメントの話

 まぁCの場合もアラインメントに注意しないといけないのだが、アラインメントを無効にしないとヘッダが正しく読み込まれない。そういえば高級言語ではアライメントなど考えないのか。

 BMPはレトロなフォーマットだがヘッダはアライメントを考慮しているのであった。だが、GIFは考慮していないのであった。

 それではアライメントとは何だろうか。実はCPUの内部ではbyte単位ではなく、2byteもしくは4byte単位で処理が行われているのである。バイナリを扱うときも2byteもしくは4byte単位で処理した方が効率が良いわけである。その単位がアライメントである。

次の様な構造体を用意したとする(GIFのヘッダだけど)

struct {
    ushort width;
    ushort height;
    uchar  field;
    uchar  color_index;
    uchar  aspect;
};

 この場合コンパイラは、どのようにメモリを確保しようとするのだろうか?

 アライメントが2byteの場合は、こうなる。

大体アライメントの所為

 ucharは1byteのはずなのにコンパイラの最適化により2byte消費される訳である……。そしてファイルの情報をアライメントを考えずにそのまま構造体に読み込ませると、黒い使われて居ない部分にデータが流し込まれてしまうのである。つまりデータが壊れるのである(CPUによっては奇数のアドレスにアクセスするだけで例外を起こす)。そういうわけでファイルからそのままデータを流し込むにはアライメントを無効化しないと行けないのである(BMPやTIFFなどのヘッダはアライメントの性質を考えて実装しているはずなのだが、相変わらず嘘ヘッダが多い……40byteと書いてあるのに中身が52byteのヘッダってなんだよ)

 Rustは、相変わらず借用とライフタイムのコツがよく分からない(ここでエラーでるの……みたいなの多い)トレイトはなんとなくコツが分かって気がする(恐らく気のせい)


この記事が気に入ったらサポートをしてみませんか?