質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.40%
GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

Q&A

解決済

2回答

410閲覧

Mintty(MinGW)上でGCCで作成したC言語のプログラムを実行すると入力と出力の順番がおかしくなる

MakotoAkai

総合スコア8

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

MinGW

MinGW(ミン・ジー・ダブリュー)は GNUツールチェーンのWindows移植版です。 ランタイムライブラリと開発ツールで構成されています。

0グッド

0クリップ

投稿2024/05/20 21:36

編集2024/05/20 21:47

実現したいこと

Mintty上で正しく動作させたい

発生している問題・分からないこと

mingwのgccでコンパイルしたファイルをmingw上で実行すると、scanfが入力されるまでprintfやputcharが実行されない。このため、入力した後にまとめて出力が実行されてしまい、入出力の順番がプログラム通りにならない。

エラーメッセージ

error

1エラーメッセージはないですが、出力の状態をキャプチャして「試したこと」欄に貼りました。

該当のソースコード

C言語

1//読み込んだ整数値の全約数とその個数を表示 2#include<stdio.h> 3 4int main(void) 5{ 6 int n; 7 8 printf("整数値:"); 9 scanf("%d",&n); 10 11 int count = 0; 12 for(int i = 1;i <= n; i++) 13 if(n % i == 0) { 14 printf("%d\n", i); 15 count++; 16 } 17 printf("約数は%d個です。\n",count); 18 19 return 0; 20}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

コンパイルされたa.exeをcmd.exe上から実行すると、正しい順番に動作しているので、コンパイラ側の問題ではなく、minttyの表示上の問題であると思われる。

.bash_profileに以下の設定を追加してみた。
export LANG=ja_JP.UTF-8
exec winpty bash

この設定だと、入出力の問題は回避できたが、文字化けする。(winptyとminttyで二重に漢字コード変換を通している??)
Windowsの漢字ファイル名は正しく表示されているが、このプログラムの出力は文字化けする。
このプログラムはUTF-8で書かれているので、SJISのみを通しているように見える。
上記のwinptyの起動をコメントアウトした上で、mintty上で実行するときにwinptyを通しても状況は同じ。
./aとwinpty ./aの挙動の違いを比較すると以下のとおり。(元の.bash_profileはコメントアウト状態)
デフォルトでは、./aは入出力順序がおかしいが漢字コードは正しい。winpty ./aは入出力順序は正しいが漢字コードがおかしい。
chcpでminttyの漢字コードを65001(UTF-8)に指定しても挙動は変わらない。
932に指定すると、./aもwinpty ./aもどちらも文字化けする。このときの出力内容は65001やデフォルトでwinpty ./aの出力と同じ形に文字化けしている。
イメージ説明

プログラム通りに出力されるなら、
最初に”整数値:”が出力されて、次にscanfで入力した値(ここでは23)が続き、その下に1と23が出力されて、最後に"約数は2個です。"と出力されるはずです。

winptyが漢字コードを正しく出力できるなら、その形で解決しても良いですしwinpty以外の解決方法があるのであれば、その方法でもよいです。よろしくお願いします。

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

仕組みはman setvbufあたりを見てもらうとして、
stdoutが端末の場合、改行を出力するまで実際に端末に表示されないことがあります。文字列はバッファーに溜まってます。

この場合の解決策は、
案1: stdoutじゃなくてstderrを使う(fprintf(stderr,"整数値:");)。人間と対話するための出力は普通はstderrを使います。それを想定して端末に割り振られたstderrは常にバッファリング無し出力のはずです。
案2: 表示したいタイミングでfflush(stdout);を呼んでバッファーに溜まっている物を出力する。
案3: 文字列の最後に\nを付けておく。
案4: あらかじめsetvbuf(stdout, (char *)NULL, _IONBF, 0);を呼んで、バッファリング無し出力にしておく。

なお、端末でなくファイルやパイプに書く時もデフォルトではバッファリングされます。速度向上のためです。
(このときは\nの特別扱い無しがデフォルト。setvbufでデフォルトから別のモードに変更可能。)

投稿2024/05/21 11:02

otn

総合スコア85458

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2024/05/21 11:11

手元の ~\msys64\usr\bin\mintty.exe だと、「整数値:」と表示されてから入力待ちになりますね。 何が違うのか分かりませんが。
MakotoAkai

2024/05/25 00:42

ありがとうございます。 printf("整数値: \n"); と fprintf("整数値: "); はどちらも挙動が変わりませんでした。 しかし、fflush(stdout);をscanfとprintfの間に入れると、意図したとおりに動作しました。 おそらくご指摘のとおり、バッファリングが原因だろうと思うのですが、娘のノートPCでだけ発生している症状のようです。 バッファリングしないとパフォーマンスが落ちるという説明を見たのですが、windowsのコマンド処理(自分はbashよりもcmd.exeの方を良く利用してきていました)ではこういった問題に出くわしたことがありませんし、特段に処理が遅いと感じたこともありませんでした。 Unix系のコマンドでは多重のパイプ処理が多様されるために必要になった仕様なのでしょうか? バッファリングのデメリットは今回感じているのですが、メリットを体感できず、何のために必要なのか理解しにくく感じています。 できれば、明示的にオフにして使用したいです。 背景の技術的な側面を補足いただけますと大変ありがたいです。
MakotoAkai

2024/05/25 00:55

Minttyの呼び出し元の実体は良く分からないのですが、Git bashに付属してきたものでした。 Windows側はC:¥Program Files\Git\git-bash.exe"を起動すると起動します。 そのターミナル上で which mintty とすると /usr/bin/mintty と表示されるので、 /usr/bin/mintty.exe とbash上から実行すると、別のMSYSのターミナルが起動します。 そのターミナル上でも同じ問題が発生しています。 Windowsターミナルやコマンドプロンプトではバッファリングによる問題は発生していません。 不足している情報があればご指摘ください。 確認して補足いたします。
otn

2024/05/25 04:53 編集

普段使ってないのですが、git-bashの端末でやってみると同じ現象で、改行しても表示されません。 Cの実行時ライブラリで、stdoutの先が端末なのかファイルなのかを調べて、端末なら行バッファリングに設定するはずなのですが。 stderrに出力すると、ちゃんとバッファリング無しのようで、改行しなくても表示されるので、端末かどうかの判断はされているようです。 バッファリングの効果ですが、端末表示の場合は、人間相手なので、普通の量の表示で速度の違いを感じることはないでしょう。 1行だと差は誤差の範囲で、数十行でも差は体感できないでしょうね。 ちょっとプログラムを書いて147MB(234万行)のテキストファイルをgit-bashの端末で表示させてみました。 入力のバッファリングはデフォルトで、出力を、 バッファリングせず1バイトずつ書く・・・781.8秒(約13分) 4096バイトずつのバッファリング・・・・120.1秒(約2分) まあ、234万行の表示が速いか遅いかはあんまりどうでも良い気がしますが。なので、端末の場合はバッファリング無しか、行バッファリングになるのが普通です。minttyの動作は謎。 ディスクに書く時は時間の差は気になります。数十倍~数百倍の差になるかと思います。パイプでもその先で何をするかで差が効く場合とあまり効かない場合があるでしょうね。 同じデータのHDDの読み書きで、同じく入力はデフォルトで、 バッファリングせず1バイトずつ書く・・・1078.4秒(約18分) 4096バイトずつのバッファリング・・・・19.9秒 (SSDに1バイトずつだと書き込み回数が気になるので、HDDでテスト) 結論としては、 「人間向けの端末への表示はstderrに書いておけば良い」 ですね。 すこしその先を補足すると、上記のバッファリングは、言語処理系のライブラリが行うバッファリングのことですが、その先はOSのバッファリングやキャッシュもあります。HDDデバイスドライバを直接使って1バイトずつ書くのだと、まずブロックを読んで1バイト書き換えてブロックを書くという風に、一回の書き込みで読み書き1回ずつ発生しますが、OSのバッファリングがあるのでそんなことまでは発生しないはず。
guest

0

mingwのgccでコンパイルしたファイルをmingw上で実行すると、
scanfが入力されるまでprintfやputcharが実行されない。

printf("整数値: "); の後に fflush(stdout); の追加で改善するような気がします。
printf() の引数の末尾に '\n' がない場合にバッファに残っていることがあり,それを出力させることができます。

C

1#include<stdio.h> 2 3int main(void) 4{ 5 int n; 6 7 printf("整数値: "); 8 fflush(stdout); 9 scanf("%d", &n); 10 11 int count = 0; 12 for(int i = 1; i <= n; i++) 13 if(n % i == 0) { 14 printf("%d\n", i); 15 count++; 16 } 17 printf("約数は%d個です。\n", count); 18 19 return 0; 20}

投稿2024/05/21 00:21

little_street

総合スコア394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MakotoAkai

2024/05/25 00:23

ありがとうございました。 fflushで解決できました。 ただ、Windows Terminal上のbashではfflushを使用せずに正常に動作していて、Mintty上ではfflushを入れないと正常に動かない理由が気になっています。 ここまでのお二人のご説明を見ると、出力のバッファリングの有無によるものなのかなと思うのですが、Minttyでバッファリングを明示的に切るスイッチなどは無いのでしょうか? 実は、娘の演習用PCの端末でこの症状が発生しているのですが、周囲の友人は正常に動作していると言っているようなのです。 何か設定をすればオフにできるのでしょうか?
MakotoAkai

2024/05/25 00:44 編集

Minttyのバッファリング設定の方法についてご存じでしたら、引き続き教えてください。
little_street

2024/05/25 04:24 編集

(専ら Windows Terminal/PowerShell で)mintty/msys2 には縁がなくお力になれませんが,下記の類似ケースが参考になるかもしれません。最後に解決策(?)も記載されているようです。 https://github.com/msys2/MSYS2-packages/issues/1565
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.40%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問