🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

2回答

1061閲覧

システムコール・ライブラリー呼び出しの優先度

moni

総合スコア27

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

1クリップ

投稿2021/02/27 05:52

以下のコードは標準入力で受け取った文字列を標準入力するだけのコードです。

C

1#include <stdio.h> 2 3const int BUF_SIZE = 255; 4char buf[BUF_SIZE]; 5 6int main(){ 7 printf("Input : "); 8 fgets(buf, BUF_SIZE, stdin); 9 printf("Output : %s", buf); 10 return 0; 11}

実行して適当な文字列を入れると以下のようになります。

shell

1Input : hoge 2Output : hoge

次に fgets の部分を read(2) に置き換えた以下を考えます。

C

1#include <stdio.h> 2#include <unistd.h> 3 4const int BUF_SIZE = 255; 5char buf[BUF_SIZE]; 6 7int main(){ 8 printf("Input : "); 9 read(STDIN_FILENO, buf, BUF_SIZE); 10 printf("Output : %s", buf); 11 return 0; 12}

すると printf("Input : ") が実行されるより前に入力待ち状態になり、実行結果は以下のようになります。

shell

1hoge 2Input : Output : hoge

このあたりの挙動は、何かしらの優先度に基づいて定められているものなのでしょうか?
ご教授いただけると幸いです、よろしくお願い致します。

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

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

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

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

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

guest

回答2

0

まず前提として、ターミナルで対話実行した場合、stdout はデフォルトで line-bufferred モードであり、改行文字出力でバッファが自動的に flush されます。( もちろん、明示的に fflush を呼んでも flush されます )
そうすると、今回のソースで、最初の printf の時点では改行が無いので出力が flush されません。

しかし、GNU/Linux で使われている glibc の場合 ( macはちょっと分かりませんが )、fgets等のstdio入力関数を呼んだところでも、連動して stdout に対して flush が行われるようになっています。
これが read の場合はそういう挙動がないので、fgets を使った版と read を使った版で、出力の flush のタイミングに差が出るということになります。

この挙動については、sleep 等で fgets のタイミングをずらすなりすれば、より実感し易いかと思います。

なお、多分これはマニュアルに載っていない挙動だとは思うのですが、伝統的に UNIX系の stdio ではそういう実装になっているらしいです。
以下、glibc のソースの該当箇所を挙げます。( 処理内容というよりもコメントをご覧ください )
出展: https://github.com/lattera/glibc/blob/master/libio/fileops.c#L497 ( どなたかの glibc のミラーリポジトリより )

fileops.c

1 if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) 2 { 3 /* We used to flush all line-buffered stream. This really isn't 4 required by any standard. My recollection is that 5 traditional Unix systems did this for stdout. stderr better 6 not be line buffered. So we do just that here 7 explicitly. --drepper */ 8 _IO_acquire_lock (_IO_stdout); 9 10 if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF)) 11 == (_IO_LINKED | _IO_LINE_BUF)) 12 _IO_OVERFLOW (_IO_stdout, EOF); 13 14 _IO_release_lock (_IO_stdout); 15 }

余談ですが、C++ では、これは std::cin.tie() によって、標準入力での入力処理時に、標準出力 std::cout の flush を連動させるかを制御できるようになっています。
参考: https://ja.cppreference.com/w/cpp/io/basic_ios/tie

投稿2021/02/27 06:54

angel_p_57

総合スコア1681

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

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

moni

2021/02/27 08:03

詳しい解説をいただきありがとうございます! sleep を用いて挙動を確認しました。また scanf など他の入力関数でも同じ挙動となることも確認しました。 何も考えずに使っていた入出力ですが、知見が深まりました。
guest

0

ベストアンサー

実行はされてるんだけど、標準出力はバッファリングされたままになってるので画面には出ていないってことですね
標準出力をフラッシュしましょう

投稿2021/02/27 06:03

y_waiwai

総合スコア88040

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

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

moni

2021/02/27 06:13

ありがとうございます!2つ目にfflush(stdout)を使用すると挙動が一致しました。 すると自然に沸く疑問として、1つ目が出力をバッファリングせずフラッシュされているのは何故なのでしょう?もしご存知なら教えていただけると幸いです。
y_waiwai

2021/02/27 06:20

単に、続く操作が標準入力に対する操作のため、そこで自動的にフラッシュされた、ってことです システムコールに、標準入力の操作だと言うのが認識されなかったんでしょう
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問