
シェルのレベルでは単に:
exec >> stdouterr.log 2>&1
とするだけで、2つのストリームを1つのファイルに出力できるようです。
ところがこれをC言語で実現することができません。例えば次のコード:
FILE *fpout,
*fperr;
setbuf ( stdout, 0 );
setbuf ( stderr, 0 );
fpout = freopen( "outfile", "wb", stdout ),
fperr = freopen( "outfile", "wb", stderr );
printf ( "処理を開始します。\n\n\n" );
fprintf(stderr, "stderrに出力します。\n" );
Msg = K_Link.LnkConvert ();
printf ( "\n\n\n処理を完了しました。\n\n\n" );
fclose ( fpout );
fclose ( fperr );
を実行すると、下記のような『outfile』ができてしまいます。
処理を開始します。
MS-DOSコマンド"mkdir /public1/public/Pic/Compile_euc/K_LIB"を実行します。
MS-DOSコマンド"cp -r /public1/publ....../K_LIB/* /publ.../K_LIB"を実行します。
MS-DOSコマンド"chmod -R u+rw /public1/pu.._euc/K_LIB"を実行します。
ファstderrに出力します。 <-<-<-<-<-<-<-<-<-<-<-<-<-<-<- 何か変?
Pic/Compile_euc/tmp.dat"をファイル"/public1/p..._LIB/Makefile"にコピー。
ファイル"/pub...p.dat"をファイル"/public....ile.gcc"にコピー。
| | | | |
| | | | |
の様に出力が壊されてしまいます。
2つのストリームからデータが出力されるタイミングがそれぞれ異なるようです。
どの様にしたらうまくいくのか助言ください。
A 回答 (5件)
- 最新から表示
- 回答順に表示
No.5
- 回答日時:
#4 に書いたようにこの動作は「処理系定義」です. 言い換えると, 「確実に実行する」方法は標準 C には存在しません.
逆に言えば「環境によっては可能」なので, どのようなコンパイラを使いどのような OS で動かすのかがわかれば安心できる方法が見つかるかもしれません. あるいは, 「あなたが作るアプリから市販のCコンパイラを起動する」方法に依存するかもしれません.
Unix 世界なら普通は dup2. Windows にも _dup2 という名前で存在してるらしい.
様々にご支援ありがとうございました。
いろいろじたばたとやってみたのですが、私には問題解決できず諦
めました。
最終的に、私が作成するソフトウエアから直接市販コンパイラを起
動するのではなく、私のソフトはコンパイラ起動のためのバッチ
ファイルを作成.....バッチファイルを起動する際に次のDOSコマン
ドを用います。
compile.bat > compile.log 2>&1
これで、バッチファイル実行中のstdout/stderrは奇麗に
compile.logファイルに収まります。
何だか『DOSコマンドを駆使する。』ことには抵抗があるのですが
仕方がありませんね。
No.4
- 回答日時:
「混ぜるのは簡単だけど分離するのは難しい」んだから, そんな変なことはしない方が吉だと思う. 少なくともこの文章では「そんなことをなぜしなければならないのか」が読み取れないし.
ちなみに「許されていません」とはなってません>#2. 「処理系定義」なので, 処理系によっては可能です... がその結果どうなるかは知らない.
皆様から早速ご連絡いただきながら、ご回答が遅くなり申し訳ありません。
取り急ぎ次のようにご連絡致します。
1.shsst14様
一般的に『禁じ手』であることは、ご指摘のとおりかもしれません。
しかしながら私の最初の質問にも記しましたとおり『シェル上のコマンドの組み合わせ
ではできるではないか。』ということです。私自身は実際に試していませんが、web上
で『できる。』と答えている方は大勢いるようです。もしかしたらDOS窓上のDOSコマン
ドを使ってもできるかもしれませんね。
シェルもCまたはC++プログラムであることを考えれば、『できない。』ことはないだろ
うと思います(私自身はできなくて困っているのですが。)。
2.chie65535様
ご指摘の内容を私はよく理解できていません。
少し時間をかけてテストしてみます。
3.OrangeCup150様
わざわざテストコードまで添付いただきありがとうございます。
少し時間をかけて確認させていただきます。
4.Tacosan様
このようなことを質問するのは次の理由です。
私が作るアプリから市販のCコンパイラを起動します。その際にDOS窓上に表示される
メッセージ全てをログファイルに納めたいのです。
私自身が作るプログラム上ならば、単に全てのメッセージをprintf()関数で書けば用は
足りるのですが、市販のCコンパイラはstdoutとstderrを区別して出力します。
つまりstdoutだけでログファイルを作ってしまうと、エラーが発生してもログを見ても
全然判らない、という間抜けなことになってしまいます。
そこで、表記のような質問をしたのでした。
No.3
- 回答日時:
・ストリームを追記モードで開く
・バッファリングをしない
でやるとこちらの環境 (Windows SDK) ではうまくいきました。
体感はできませんが、常識的に考えてバッファリングをしないのでパフォーマンスはすごく悪くなっていると思います。
論理的には、ファイルストリームに対してバッファリング無しでアクセスされる、追記モードを使用するので処理の整合性は保障されると納得はできました。推測ですがバッファリングを使用すると非同期に処理が行われる(マルチスレッド化する)のでうまくいかないが、バッファリングを無効にするとシングルスレッドで処理が行われるのでうまくいくのでしょう。
以下、テストコードです。参考までに。
#include <stdio.h>
#define QUOTE(str) #str
#define NUM_QUOTE(num) QUOTE(num)
#define FILE_LINE __FILE__ " の " NUM_QUOTE(__LINE__) " 行目"
int main(int argc, char **argv)
{
FILE *o, *e, *info;
int result;
info = fopen("info", "w");
o = freopen("outfile", "a", stdout);
if (o == NULL) {
fprintf(info, "ERROR: " FILE_LINE "\n");
fclose(info);
return 1;
} else {
fprintf(info, "OK: " FILE_LINE " freopen(stdout)\n");
}
e = freopen("outfile", "a", stderr);
if (e == NULL) {
fprintf(info, "ERROR: " FILE_LINE "\n");
fclose(info);
return 1;
} else {
fprintf(info, "OK: " FILE_LINE " freopen(stderr)\n");
}
result = setvbuf(stdout, NULL, _IONBF, 0);
if (result != 0) {
fprintf(info, "ERROR: " FILE_LINE "\n");
fclose(info);
return 1;
} else {
fprintf(info, "OK: " FILE_LINE " setvbuf(stdout)\n");
}
result = setvbuf(stderr, NULL, _IONBF, 0);
if (result != 0) {
fprintf(info, "ERROR: " FILE_LINE "\n");
fclose(info);
return 1;
} else {
fprintf(info, "OK: " FILE_LINE " setvbuf(stderr)\n");
}
printf("処理を開始します\n");
fprintf(stderr, "stderr に出力します\n");
printf("処理を終了しました。");
result = fclose(o);
if (result != 0) {
fprintf(info, "ERROR: " FILE_LINE "\n");
fclose(info);
return 1;
} else {
fprintf(info, "OK: " FILE_LINE " fclose(o)\n");
}
result = fclose(e);
if (result != 0) {
fprintf(info, "ERROR: " FILE_LINE "\n");
fclose(info);
return 1;
} else {
fprintf(info, "OK: " FILE_LINE " fclose(e)\n");
}
fclose(info);
return 0;
}
No.2
- 回答日時:
>どの様にしたらうまくいくのか助言ください。
CのI/Oストリームでは、1つのファイルを同時に2回以上オープンするのは許されていません。
で、以下のような事は絶対にやっちゃ駄目ですが、
stdio.hを見てみると
typedef struct
{
(中身は略)
} FILE; /* This is the FILE object */
の付近に
extern FILE _streams[];
とか
#define stdin (&_streams[0])
#define stdout (&_streams[1])
#define stderr (&_streams[2])
とかって記述があります。
これは、stdoutはFILE型構造体の配列_streamsの1の要素のポインタ、同様にstdoutはFILE型構造体の配列_streamsの2の要素のポインタ、と言う事です。
なので
#undef stderr
#define stderr stdout
とやってしまえば、stdoutもstrerrも「同じ内容のストリームオブジェクト」を意味します。
但し、ライブラリ内で&_streams[2]を参照している箇所は「そのまま変化しない」のでご注意を。
でも、こんな事は絶対にやっちゃいけません。
本当なら、1行書き出すたびに、fopenとfcloseを繰り返して「1つのファイルを同時に2回以上オープンしない」と言う状態を保たないといけません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ファイル形式またはファイル拡...
-
コマンド(例えばls)の出力結果...
-
シェルコマンドの 2>&1 とはど...
-
ファイル出力の場所を指定
-
CSV形式に変換
-
C言語初心者の質問失礼します。
-
バイナリ形式のXMLファイルを読...
-
C言語でBMPファイルの内容を表...
-
vba ActiveSheet.pasteを使った...
-
OpenDialog1->FileNameについて
-
FTPでputすると空ファイルが出...
-
どんなプログラムを書いても指...
-
「UNCパスはサポートされません...
-
フルパスから最後のディレクト...
-
LSI C-86 v3.30c 試食版について
-
SWTとSwingの違い
-
dataファイルをxtxファイルにす...
-
VB.NETで他のプロジェクトで作...
-
バッファとは何ですか
-
VB6.0で作ったプロジェクトが起...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ファイル形式またはファイル拡...
-
Acccess レポートをグループ別...
-
CSVファイルを任意の場所に出力...
-
テキストファイルに改行コード...
-
コマンド(例えばls)の出力結果...
-
シェルコマンドの 2>&1 とはど...
-
ファイルの文字コードをUTF-8に...
-
(VBA)書式が変更されてしまい...
-
BitBltについて。
-
SendKeys "^V", True(貼り付け...
-
Excel のページを Jpegファイル...
-
【ExcelVBA】UTF-8(BOM無)でC...
-
VB.NETでExcelファイルを出力す...
-
AccessVBA複数レポート条件毎に...
-
raw形式からbmp形式への書き込...
-
Paiza Cloudです。 どうやれば...
-
OCRで起こしたテキスト文字をCS...
-
Wordマクロで指定したフォルダ...
-
C言語での縦方向のファイル出力...
-
VC++でUTF-8のファイルを出力し...
おすすめ情報