コンピューター:C言語講座:freopenについて
概要
最近仕事でWEB関連の開発を行うことが多く、C言語でCGIを作る機会が多いのですが、意外と大変なのがデバッグで、HTTPサーバデーモンから勝手に起動されるのでデバッガをアタッチすることが難しく、また環境変数などをセットしないと単体で実行できない場合が多いので大変です。標準エラー出力にデバッグプリントを出してもApacheではエラーログに出てくれるのですが、ネットスケープサーバなどではサーバエラーになってしまいます。エラーになるとどんなHTMLを出したかもブラウザでも分からず、実に困ったものです。
もっとも有効なのは/tmpあたりにログファイルをつくり、追加書き込みモードでログを吐かせてデバッグすることですが、ちょっとしたことならともかく、生成したHTMLの内容を見たい、といったレベルになるとデバッグ用のfprintf()を埋め込むだけで一苦労になります。
そこで意外と便利なのが今回紹介する、freopen()です。すでにオープンしてあるストリーム(ファイルポインタ)を別のものに変更することができます。CGIで便利なのはもちろん標準出力をデバッグ用のログファイル等に変更することです。こうすると、freopen()を1行追加するだけでprintf()などの標準出力を対象とした出力がそのままのソースでログファイルなどに出力できます。
まあほかにはあまり使い道がないかも知れませんが、知っていると便利な関数ではないでしょうか。
サンプル
単純にメッセージを表示するだけのCGIにデバッグ用にfreopen()を使ってみます。
#include <stdio.h> #include <stdlib.h> #include <string.h>void main(argc,argv) int argc; char *argv[]; { FILE *fp;fp=freopen("/tmp/debug.log","w",stdout);printf("Content-type:text/html\n\n"); printf("<html>\n"); printf("<head>\n"); printf("<META HTTP-EQUIV=\"Content-type\" CONTENT=\"text/html; charset=x-euc-jp\">\n"); printf("<title>テスト</title>\n"); printf("</head>\n"); printf("<body>\n"); printf("<p>テストです</p>\n"); printf("</body>\n"); printf("</html>\n"); }
こんなものCGIじゃなくてHTMLファイルをつくればいいじゃないか、と言われそうですが、サンプルなので勘弁してください。デバッグ用に追加するのはFILE
*fp;の宣言と、fp=freopen();の2行だけです。これで以降のprintf()の出力がすべてファイルに出力されるようになります。
もちろん本来の標準出力には何も出力されなくなりますから、WEBサーバはエラーとなりますが、とりあえずCGIを正常に起動してもらって、その結果を見ることができます。
なお、本当は最後にfclose(fp);を入れるべきですが、デバッグに一時的に使うということで、省略してます。もちろんプロセス終了時にはすべてのファイルはクローズされるので問題はないですが、几帳面な方はちゃんとクローズしましょう。
まとめ
この使い方に気が付くまではfreopen()は知っていましたが使う気もしなかったのでした。はじめはどうやってstdio.hにマクロ定義されている標準出力のファイルポインタを別ファイルポインタに切り替えられるんだ、と不思議でしたが、良く考えるとdup2()システムコールでできますね。興味のある方はやってみましょう(あまり深く考えなければ簡単にできましたが、FreeBSDのfreopen()のソースを見るともっといろいろな処理をしてました)。