今回は、C言語でファイル操作によく使うFILE型に関する迷信です。FILE型と書きましたが、このように呼ぶ人は世間では意外に少なく、多くの人はFILE構造体と呼びます。では、FILE型は常に構造体であると考えてよいのでしょうか? 答えはもちろんノーです。

その根拠を示すために、まずはJIS X3010:2003におけるFILE型の記述を引用してみましょう。

FILEは,ファイル位置表示子,結び付けられたバッファ(もしあれば)へのポインタ,読取りエラー又は書込みエラーが起こったかどうかを記録するエラー表示子(error indicator),ファイルの終わりに達したかどうかを記録するファイル終了表示子(end-of-file indicator)などストリームを制御するために必要なすべての情報を記録することのできるオブジェクト型とする。

いろいろな情報を格納する必要がありますので、普通に考えれば構造体を使うことになるのでしょうが、構造体型ではなくオブジェクト型となっています。オブジェクト型というのは、関数型や不完全型ではないオブジェクトを表現するための型で、具体的には、算術型・ポインタ型・構造体型・共用体型・配列型の総称です。ですから、必ずしも構造体である必要はないのです。

とはいえ、多くの実装ではFILE型は構造体になっています。これは素直な実装ではありますが、本来隠蔽すべき実装の詳細をユーザーにさらすことになるためデメリットもあります。一部の関数(putcやfeofなど)をマクロやインライン関数として記述できなくなるものの、より堅牢な実装のためには、<stdio.h>ヘッダでは

のように、FILE型は宣言だけにとどめ、各関数の実装を行っている翻訳単位でのみ構造体の宣言を行うようにした方がよさそうです。しかし、残念ながらこのような実装は許されません。なぜなら、FILE型はオブジェクト型でなければならず、構造体の宣言だけでは不完全型であってオブジェクト型にはならないからです。