関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
大した情報でも無いのですが、たまに標準出力をアンバッファリングにしたいときがあります。
少しだけしか出力しないプロセスとか、出力が改行しないものとか。
そのような場合にデフォルトの状態(ttyの場合はラインバッファ(_IOLBF)、パイプなどではフルバッファ(_IOFBF))で実行するとプロセスが終わるまで出力が出ない場合があります。
そういうときは、setbuf か setvbuf を使ってアンバッファリングにしてやると良いときがあります。
ついでに、glibc固有ですがバッファモードを調べるやり方もサンプルに載せてあります。
サンプル
app.c
#include <stdbool.h> #include <stdio.h> #include <stdio_ext.h> // glibcが提供する標準I/Oの拡張機能を定義したヘッダファイル (glibc固有) #include <stdlib.h> #include <unistd.h> static void print_msg(const size_t count); int main(int argc, char *argv[]) { // glibcはバッファを遅延割当するため、実際に出力が行われるまでバッファを割り当てない。 // (ラインバッファやフルバッファの場合に、一度も出力していないとバッファサイズが0バイトで表示される) // 本サンプルではバッファサイズを見たいので、意図的に一度出力を行っておく。 printf("[start]\n"); bool use_stdbuf = (argc >= 2) ? true : false; if (use_stdbuf) { // 標準出力をアンバッファリングに設定 setbuf(stdout, NULL); } #ifdef __GLIBC__ // バッファリング設定を確認 { size_t buf_size = __fbufsize(stdout); printf("バッファサイズ: %zu bytes\n", buf_size); bool is_line_buffer = __flbf(stdout) != 0; printf("ラインバッファ?: %s\n", is_line_buffer ? "はい" : "いいえ"); bool is_unbuffered = (buf_size <= 1 && !is_line_buffer); if (is_unbuffered) { printf("状態: アンバッファ (_IONBF)\n"); } else if (is_line_buffer) { printf("状態: ラインバッファ (_IOLBF)\n"); } else { printf("状態: フルバッファ (_IOFBF)\n"); } } #endif // 確認 { const int count = 5; print_msg(count); } } static void print_msg(const size_t count) { for (size_t i = 0; i < count; i++) { // // バッファリング有りの場合、高確率で即座に表示されないことが多い. // アンバッファリングの場合、即座に表示される // // つまり、以下の場合だと大抵の環境では // - バッファリング : 5秒後にまとめて出力 // - アンバッファリング: 即座に出力 // となる // fprintf(stdout, "[%ld]", i); sleep(1); } printf("\n"); }
Taskfile.yml
# https://taskfile.dev version: '3' vars: APP: app env: CC: gcc CFLAGS: -g3 -O0 -std=c99 -Wall -Wextra -Wno-unused-parameter tasks: default: cmds: - task: build - task: run build: cmds: - $CC $CFLAGS -o {{.APP}} {{.APP}}.c run: cmds: # 普通に実行 - ./{{.APP}} - cmd: echo '---------------------------------' silent: true # stdbufを設定してアンバッファリングにして実行 - ./{{.APP}} 1 - cmd: echo '---------------------------------' silent: true - ./{{.APP}} | tee out.txt - cmd: echo '---------------------------------' silent: true - ./{{.APP}} 1 | tee out.txt
実行
$ task task: [build] $CC $CFLAGS -o app app.c task: [run] ./app [start] バッファサイズ: 1024 bytes ラインバッファ?: はい 状態: ラインバッファ (_IOLBF) [0][1][2][3][4] --------------------------------- task: [run] ./app 1 [start] バッファサイズ: 1 bytes ラインバッファ?: いいえ 状態: アンバッファ (_IONBF) [0][1][2][3][4] --------------------------------- task: [run] ./app | tee out.txt [start] バッファサイズ: 4096 bytes ラインバッファ?: いいえ 状態: フルバッファ (_IOFBF) [0][1][2][3][4] --------------------------------- task: [run] ./app 1 | tee out.txt [start] バッファサイズ: 1 bytes ラインバッファ?: いいえ 状態: アンバッファ (_IONBF) [0][1][2][3][4]
結果をテキストで見ると同じに見えますが、アンバッファリングを設定していない場合は、5秒後に一気に一行分出力されます。
参考情報
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。