Version 5.18
すべての道は API に通ず!
「というわけで、 std::ifstream::open() の中を見ていったら」
if (valid[n] == 0 || (fp = fopen(name, mods[n])) == 0)
「というコードが出てきました」
『この fopen() って、ランタイムの fopen() ??』
「そう、つまり iostream はランタイムを利用してファイル入出力をしてる
んです!」
『へーっ、ま、 iostream は標準 C++ ライブラリ、ランタイムは標準 C ラ
イブラリ、使っててもおかしくないけど……でもそういう古いの使ってるっ
ていうのはやっぱ不思議かも』
「古い新しいっていうより、ローレベルハイレベルってことかも」
『前回の話ね。ファイル使うのはローレベル、クラス使って便利にしてるの
がハイレベル』
「 iostream はハイレベルの部分として使いやすくしてる、で、ローレベル
の部分は昔ながらのランタイムに任せてるってことだね」
『そういうもんなんだ』
「さて! 今度はこの fopen() の中に入ってみましょう!」
『ええっ、入れるの?』
「 Visual C++ にはランタイムのソースファイルが付いてるからね」
『……ソースファイル……』
「宣言が入ってるのがヘッダーファイル、定義が入ってるのがソースファイ
ル」
『あー、 .h と .cpp ね』
「ランタイムのソースファイルには定義部、つまり関数の本体が入ってるか
ら、それを見て fopen() がどうなってるか見てみましょう」
『難しくない?』
「難しい部分は無視しましょう」
『うっ適当……』
「えっと、今の std::ifstream::open() の中の fopen() から入ってもいい
し、 fopen() 実際に呼び出すコード書いてそっから入ってもいいけど」
『 std::ifstream::open() からいこっとブレークポイント設置!』
「んじゃ入って」
『【中カッコに入る】ボタンでステップイン! _tfopen() って関数に入っ
た』
「これが fopen() の中身だね。【中カッコに入る】ボタンを2回押して」
『 _tfsopen() に入った』
「下の方に」
retval = _openfile(file,mode,shflag,stream);
「って行があるからこの _openfile() に入って」
『【中カッコを飛び越える】ボタンを……』
「あーっと、それでもいいけど、この行をクリックしてから【カーソル行の
前まで実行】ボタン押してもいいかな」
『それどのボタン?』
「【中カッコの左上に右向き矢印】のボタン」
『ぽちっと。あっ一発で!』
「他にもブレークポイントを設置して実行ボタンとかね」
『よーするにいろんな方法でできるようにってことね』
「そゆこと」
『んじゃ _openfile() の中へゴー!』
「下の方に」
if ((filedes = _tsopen(filename, modeflag, shflag, CMASK)) < 0)
「があるから」
『 _tsopen() の中に入ればいいんだよね、クリックして【カー(略)実行】
で……っとなんか変なダイアログ出た!』
「【あいまいさの解決】ダイアログだね。似たような関数がふたつあって、
Visual C++ がどっちか判らないときにこのダイアログが出ます」
『あたしもわかんない〜』
「こういうときは、頭に w が付いてない方を選んで」
『じゃー _openfile() っての。ん、どうなったのかな?』
「 _tsopen() のある行まで来たから」
『あ、そっか、じゃーステップイン!』
「この _tsopen() の下の方に……」
if ( (osfh = CreateFile( (LPTSTR)path,
「って行があるでしょ」
『うん、んじゃこの行まで飛んでステップ』
「ちょいまちっ!」
『な、なに? CreateFile() の中に入るんじゃ…… CreateFile() ?』
「どっかで聞いたこと」
『ああっ!! これって…… API の CreateFile() なの?』
「そゆこと。やっとたどり着いたね」
『ど、どーゆーこと?』
「つまり、 fopen() でファイルを開くってことは、間接的に CreateFile()
を呼んでファイルを開くってこと」
『……つまりランタイム使ってると思ったら、ホントは API 使ってたと』
「そういうこと」
『ってことは iostream も API 使ってるってことで……あのーもしかして』
「うん、 MFC も API 使ってる」
『ええ〜!! なに、結局ファイル開くのって API 使ってるってことな
の!?』
「あ、もちろん開くだけじゃなくて、ファイル入出力は全部 API 使ってる
んです」
『なんか……ちょっと驚いたかも』
「驚く前に MFC の方も確認しておこうか。とりあえず【実行】ボタン押し
て」
『フツーに動くようにしてダイアログ閉じて、ね』
「そしたら」
void CFileTestDlg::OnBtnShow()
{
CStdioFile cStdFile;
cStdFile.Open( "Data.txt", CFile::modeRead );
return;
// 以下取っておきましょう
『いつものパターンね』
「テスト用だから開けたかどうかのチェックはナシ。じゃ、
CStdioFile::Open() 呼んでる行にブレークポイントを設置して」
『ステップイン! CStdioFile::Open() に入った』
「6行くらい下に CFile::Open() を呼んでるところがあるから」
『これにステップイン! これって、いわゆる親クラスのメンバ関数に入っ
てるんだよね』
「そうそう、ファイル開いたりする機能は親クラスの CFile の方にあるから
ね」
『 CFile::Open() の中に入って……ああっ!!』
HANDLE hFile = ::CreateFile(lpszFileName, dwAccess, dwShareMode,
「というわけで、 MFC も API を使ってファイルを開いていましたとさ」
『めでたしめでたし、ってあのねー』
「簡単にまとめると」
iostream > fopen > CreateFile
CStdioFile::Open() > CreateFile
「って感じだね」
『最終的に API 呼んでるっていうのは、さっきのローレベルって話?』
「そういうことだね。まず基本的に、ファイル操作ってのは危険なことだっ
ていう認識が必要」
『そりゃそうよね、ウィンドウズの重要なファイルとか、間違えて書き換え
ちゃったりしたらまずいわけだし』
「だから、ファイル操作は API でしかできないようになってるわけ」
『 API 以外にはファイル操作する方法がないってこと?』
「さらにローレベルな機能使えばあるけど、基本的にはそういうこと。 API
だけが〈ファイル操作のための手段〉として提供されているわけ」
『そうやって問題が出ないようにしてるんだ』
「だから、ランタイムも iostream も MFC も、ファイル操作をするときに
は API を呼んでるわけ」
『ランタイムなんてなんか直接してそうだったのに』
「ランタイムだって人の作ったものだからね」
『どゆこと?』
「ライブラリの作られる順番は、 API が最初。まず API が作られます」
『うんうん』
「次にランタイムを作ります。ランタイムを作る人は〈ファイル操作をする
ときには API を使うんだ〉ってことを知って、 API を使うプログラムを組
むわけ」
『そっか、ランタイムだってそーゆーふーにプログラムとして作られるんだ
もんね』
「 iostream も MFC もそう。ライブラリって最初からあるし何気なく使え
るから〈なんかすごい〉とか思うかもしれないけど、所詮人の作ったもの」
『確かに』
「得体の知れないことしてそうでも、実際はそうでもないってことをちゃん
と分かっておいて」
『つまりライブラリの中身を見ようってこと?』
「それもひとつ。分からない部分も多いと思うけど、積極的に見ていって欲
しいかな。数少ない〈自分以外の人が作ったプログラム〉だしね」
『例にいいってことね。もうひとつは?』
「ランタイムとかは見られるけど、 API の中身は見られないから」
『あ、そういえばそうだよね。ソースファイル公開してないから?』
「 API の中身はすなわちウィンドウズの中身、だからね」
『あーそーいえばそーゆー訴訟してたね』
「で、 API の中身は見えないけど、見えなくったって、結局は得体の知れ
ないことしてるわけじゃないんだ、っていうことを憶えといて」
『 API の中身だって、誰かが作ったプログラムなんだ、ってこと?』
「そういうこと! まずは、どんなアプリもプログラムも、自分と同じプロ
グラマーが作ったんだっていう認識が大事」
『つまり、自分にだってそういうものは作れる!』
「そこまでは言えないけど、でもそういう考えは重要。とんでもない変なこ
としてるわけじゃなく、ちゃんとしたプログラムなんだっていうイメージが
重要だね」
『まとめ! 結局 API を呼んでファイル操作してる!』
「 API だけでできるようになってるってこと」
『ランタイムとかも、意味不明な操作じゃなくて、 API を使うっていう普
通のことをしてファイル操作してる!』
「だから、どんなプログラムも普通のプログラムなんだ、って思いましょう」
/*
Preview Next Story!
*/
『そんな感じのこと、 LPCTSTR の時も言ってたよね』
「重要なことだから何度もってことで」
『だからどんどん長くなるんじゃない?』
「ぎくっ」
『というわけで次回』
< Version 5.19 ファイル読み込みをブラッシュアップ! >
「につづく!」
『ってゆーか Ver 5 っていつまで続くの?』
「もうすぐ半年になっちゃうね……」