在 C 語言重新整理 stdout 輸出流

Jinku Hu 2023年10月12日
  1. 在 C 語言中使用 fflush 函式來重新整理 stdout 輸出流
  2. 在 C 語言中使用 printf 函式演示 fflush 行為
在 C 語言重新整理 stdout 輸出流

本文將演示關於如何在 C 語言中重新整理 stdout 輸出流的多種方法。

在 C 語言中使用 fflush 函式來重新整理 stdout 輸出流

C 標準庫提供了一個 I/O 庫,即 stdio,它基本上代表了在使用者空間中進行的 I/O 操作的緩衝版本,從而提高了常見用例的效能。一般來說,訪問檔案和對檔案進行操作是由作業系統服務提供的,因此,使用者最終需要系統呼叫,例如開啟一個檔案。頻繁的系統呼叫會使程式的執行速度變慢,因為它需要訪問作業系統的核心資料結構並來回傳輸控制。因此,在使用 stdio 函式呼叫時,C 庫會維護一些緩衝區來處理輸入/輸出操作。

如果使用者需要對核心緩衝區進行強制寫入,則需要對 fflush 函式提供的給定流進行重新整理。fflush 需要一個 FILE 的單引數,指向給定流的指標。請注意,fflush 對輸出流強制執行寫功能,同時丟棄輸入流的任何緩衝資料(有可尋檔案)。如果引數是 NULL,它將重新整理所有開啟的輸出流。

注意,fflush 並不能確保寫入的資料被物理儲存,因為這需要核心緩衝區被重新整理(可以使用 fsync 呼叫來完成,請參見這裡)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  char *username;
  size_t len;
  int lnmax = 256;

  username = malloc(lnmax);
  if (username == NULL) perror("malloc");

  printf("Username: ");
  fflush(stdout);
  if (fgets(username, lnmax, stdin) == NULL) exit(EXIT_FAILURE);

  printf("Your username is set to - %s", username);

  exit(EXIT_SUCCESS);
}

輸出:

Username: tmp
Your username is set to - tmp

在 C 語言中使用 printf 函式演示 fflush 行為

請注意,有些流(如 stderr)是沒有緩衝的。相反,隱含寫入 stdout 流的 printf 函式是有緩衝的,如果我們在下面執行每次迭代列印一個字元的無限迴圈,直到內部緩衝區滿了才會向流輸出內容。因此,下面的程式碼示例的結果是突發列印 bullet 字元。請注意,我們每次迭代都呼叫 usleep 函式,以減慢人眼的執行速度,以便於清晰地觀察到。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  while (1) {
    printf(".");
    usleep(1e3);
  }

  exit(EXIT_SUCCESS);
}

另外,如果我們用 fprintf 代替 printf 的呼叫,列印到 stderr 流,就會產生每秒鐘一個字元的迭代列印行為。再次強調,每次迭代的 1 秒延遲只是為了保證良好的演示效果。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  while (1) {
    fprintf(stderr, ".");
    sleep(1);
  }

  exit(EXIT_SUCCESS);
}

最後,如果我們需要在 stdout 流上模仿前面示例程式碼中看到的相同行為,我們可以在 printf 函式後新增 fflush 呼叫。這將迫使 C 庫緩衝區在每次迭代時寫入核心緩衝區,從而產生類似的行為。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  while (1) {
    printf(".");
    fflush(stdout);
    sleep(1);
  }

  exit(EXIT_SUCCESS);
}
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 創辦人。Jinku 在機器人和汽車行業工作了8多年。他在自動測試、遠端測試及從耐久性測試中創建報告時磨練了自己的程式設計技能。他擁有電氣/ 電子工程背景,但他也擴展了自己的興趣到嵌入式電子、嵌入式程式設計以及前端和後端程式設計。

LinkedIn Facebook

相關文章 - C IO