2021/4/14日 追記
この記事に記載したパッチファイルに一部ミスがありましたので修正しました。
また、bmp.cについては編集しなくても問題ないと判断したためパッチファイルを取り下げています。
学校でビットマップ画像を加工する実験がありました。
そこでは、静岡大学の安藤和敏先生が作成されたライブラリbmp.h及びbmp.cを用いて画像を加工するのですが、Linuxとmacでは画像を読み込む際(ReadBmp()関数)に次のようなエラーが発生したので記事にしておきます。
Error: Bmp_width = 0 > 1000 = MAXWIDTH!
発症環境
このエラーが発生するのは次の環境のユーザーです。
- 64bit Linux系OSを搭載したPC
- 64bit mac OSを搭載したPC
- 64bit Linux系OSの機能をもつソフトウェアがインストールされたPC(WSLやVirtualBoxなど)
原因
この問題が発生する原因はLLP64のライブラリをLP64のコンピュータ上で実行しているという点です。
LLP64とLP64とは
LLP64、LP64とはコンピュータが採用している各型のサイズを取り決めたデータ型モデルです。
LLP64とLP64では一部の型サイズが異なります。
型 | char | short | int | long | long long | ポインター |
---|---|---|---|---|---|---|
LLP64 |
8bit
|
16bit
|
32bit
|
32bit
|
64bit
|
64bit
|
LP64 |
8bit
|
16bit
|
32bit
|
64bit
|
64bit
|
64bit
|
表にあるとおり、実はLLP64ではlong型が32bit=4byteであるのに対し、LP64ではlong型は64bit=8byteもあるんです。
そのため、long型を32bitだと思いこんで使用していると今回のように困ったことになります。
今回の場合、ReadBmp()関数内ではファイルヘッダーに書き込まれている画像の高さ/幅 情報を取得する際にlong型のバイト数分、つまり8byteも読み出してしまうことが原因で必要以上のサイズとなってしまっています。
ビットマップ画像のフォーマットを確認してみると、ファイルヘッダーに記載されている高さ/幅情報はそれぞれ4byteです。
解決策
解決方法は単純で、long型で定義されているBmp_height及びBmp_widthをint型にするだけでです。
ただし、この解決方法は暫定的なものなので、C99/C++11に対応しているコンパイラでコンパイルできる場合であればint型でなくint32_t型を使用します。
この型はLLP64/LP64問題が発生したことから生まれた型で、この型を使用すれば32bitのint型であることが保証されます。
以下が差分情報です。
このpatchfileをbmp.hに適用してあげれば動作すると思います。
patchfileの適用方法は調べてください。
あとがき
私がこの問題に遭遇したのはmacで、解決するのに1時間ぐらいかかりました。
最初はビットマップ画像を正しく読み込めていないのだろうとコンパイル引数を確かめたりしていましたがうまくいかず、macはビッグエンディアンなのかもしれないと思ってちょっと確認するもリトルエンディアンで問題なし。
ビットマップ画像のファイルヘッダー情報と読み込んできた情報が違うのかもしれないと思ってhexdumpを使ってビットマップ画像と変数の中身を比較していました。
結果4byteの範囲を8byte分も取得していたことがわかり、満足感を得られました。
ちなみに実験は終わりませんでした。