64bitコードへの移植心構え その3

というわけで、やっぱりでました。前回からの続編です。

ほとんど必要な要素は前回でいっているのですが、ちょっと変な問題となりそうなstdioを使ったファイル処理の部分をやってみます。

といってもそれほどおもしろいものでもないです。Linux系(GCC)とWindows系(VC++)ではこの辺に微妙な差があるのでそれを意識しながらやってみます。

ちょっとした注意点

C言語標準(ANSI)のライブラリで使うファイル処理で問題となるのは基本的にはfseek,ftellといったファイルの読み込み位置の変更処理になります。

なお、似たようなことをするものにfgetposとfsetposがありますが、これを使って任意の位置に読み込み位置を移動する、といった処理はできないと思った方がいいです。

あくまでこの二つは「現在の位置を取得して何かの動作をした後に元の状態に戻す」ことを目的としています。それ以外の処理では使用できません。

(fpos_tという定義が何になるかはコンパイラが自由に決定できるため、これを使って「直接」の動作は無理だと思います)

Windows側で64bit値を使ったランタイムファイル処理

VC++ではfseek,ftellともどちらで(32bit実行バイナリでも64bit実行バイナリでも)32bitとなるlongでしか扱えません。

これを解除するには_fseeki64_ftelli64という関数を使って処理します。これならファイルサイズが4GBを超えても扱うことができます。

それぞれfseekとftellのlong型の部分を__int64型(64bit符号付き整数)に変更したバージョンです。

FILE *fp; __int64 size;
_fseeki64(fp,0,SEEK_END);
size = _ftelli64(fp);
_fseeki64(fp,0,SEEK_SET);

Linux側で64bit値を使ったランタイムファイル処理

GCCでは32bit実行バイナリではlongを32bit値として扱い、64bit実行バイナリでは64bit値として扱うため、この部分の動作が異なります。

64bit実行バイナリでは自動的に64bit値となるので問題は一切無いのですが、32bit実行バイナリの時に4GBを超えるファイルが正しく扱えなくなってしまいます。

両方で64bit値を使うためにはfseekoftelloを使います。

それぞれfseekとftellのlong型の部分をoff_t型(コンパイラ依存)に変更します。このとき、stdio.hのインクルード前に

#define _FILE_OFFSET_BITS 64

という定義があるときは、off_tは64bit符号付き整数と定義され、これを使ってファイルサイズが4GBを超えるファイル処理ができます。

FILE *fp; long long size; off_t offset;
fseeko(fp,0,SEEK_END);
offset = ftello(fp);
fseeko(fp,0,SEEK_SET);
size = (long long)offset;

どちらにもいえることですが、fseek,ftellとfseek,ftellの拡張処理を混ぜないようにしてください。混ぜると整合がとれなくなって大変です。

また、どちらの拡張処理ともANSIの関数ではないので対応していないコンパイラが当然あります。(_fseeki64はGCCでは使えませんし、fseekoはVC++では使えません)

まあ、本来なら_statを使ってファイルサイズを取得するのですが、そのときはstat構造体を出したくなかったのとstat構造体のst_sizeメンバが本当にファイルサイズを支えられるだけの変数サイズがあるかを確認してから使ってくださいね。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

この記事のトラックバック用URL