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

Jinku Hu 2023年1月30日 2021年2月28日
  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 <unistd.h>
#include <time.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);
}
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn

相關文章 - C IO