ZetCode

C fflush 函数

最后修改日期:2025 年 4 月 6 日

输出缓冲是 C 编程中的一个关键概念,它影响数据何时出现在输出流中。fflush 函数让您可以控制这种行为,确保数据在需要时被写入。本教程将深入解释 fflush,涵盖其目的、常见用例和潜在的陷阱。通过实际示例,您将学会如何在程序中有效地使用 fflush

fflush 是什么?

C 语言中的 fflush 函数强制将任何缓冲的输出数据立即写入关联的输出流。它接受一个参数:指向您要刷新流的 FILE 指针。对于输出流,fflush 会写入任何未写入的数据。对于输入流,其行为由实现定义。该函数成功时返回零,错误时返回 EOF

使用 stdout 的基本 fflush 用法

本示例演示了 fflush 与标准输出流最常见的用法。

basic_fflush.c
#include <stdio.h>

int main() {
    printf("This will appear immediately");
    fflush(stdout);  // Force output to appear now
    
    // Some time-consuming operation
    for (int i = 0; i < 100000000; i++);
    
    printf("\nThis might appear later\n");
    return 0;
}

没有 fflush,由于缓冲,第一个 printf 输出可能不会立即出现。fflush(stdout) 调用确保文本在耗时的循环之前显示。第二个 printf 不需要刷新,因为 \n 通常会自动刷新缓冲区。

刷新文件输出

学习如何将 fflush 与文件流一起使用,以确保数据被写入磁盘。

file_fflush.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("output.txt", "w");
    if (fp == NULL) {
        perror("Error opening file");
        return 1;
    }
    
    fprintf(fp, "Important data that must be saved");
    fflush(fp);  // Ensure data is written to disk
    
    // Critical section where program might crash
    // Without fflush, data might be lost
    
    fclose(fp);
    return 0;
}

本示例展示了 fflush 如何防止数据丢失。fprintf 写入文件缓冲区,但数据可能尚未在磁盘上。fflush(fp) 强制执行写入操作,这在潜在的崩溃点之前至关重要。始终记住在完成文件操作后仍然调用 fclose

fflush 与输入流

了解 fflush 用于输入流时的行为。

input_fflush.c
#include <stdio.h>

int main() {
    int num;
    char ch;
    
    printf("Enter a number: ");
    fflush(stdout);  // Properly flush output before input
    
    scanf("%d", &num);
    
    // Clear input buffer
    while ((ch = getchar()) != '\n' && ch != EOF);
    
    printf("Enter a character: ");
    fflush(stdout);
    
    scanf("%c", &ch);
    printf("You entered: %c\n", ch);
    
    return 0;
}

在这里,fflush(stdout) 确保提示在等待输入之前显示。请注意,fflush(stdin) 在标准 C 中是未定义行为。要清除输入缓冲区,请按所示读取字符直到 \nEOF。此方法在不同平台之间具有可移植性。

用于调试的 fflush

使用 fflush 确保调试消息立即出现在日志文件中。

debug_fflush.c
#include <stdio.h>
#include <stdlib.h>

void critical_function() {
    FILE *log = fopen("debug.log", "a");
    if (log == NULL) return;
    
    fprintf(log, "Entering critical function\n");
    fflush(log);  // Ensure log entry is saved
    
    // Simulate a crash
    if (rand() % 5 == 0) abort();
    
    fprintf(log, "Exiting critical function\n");
    fclose(log);
}

int main() {
    for (int i = 0; i < 10; i++) {
        critical_function();
    }
    return 0;
}

本示例演示了 fflush 如何帮助调试。如果没有刷新,程序崩溃时可能会丢失日志消息。abort 模拟崩溃,但由于 fflush,我们总是看到“Entering”消息。此技术对于诊断不稳定程序的问��很有价值。

fflush 与 stderr

了解为什么很少需要 stderrfflush

stderr_fflush.c
#include <stdio.h>
#include <unistd.h>

int main() {
    fprintf(stderr, "Error message 1 (unbuffered)\n");
    
    fprintf(stdout, "Normal output (buffered)");
    sleep(2);  // Notice stdout doesn't appear immediately
    
    fprintf(stderr, "Error message 2 (still unbuffered)\n");
    
    fflush(stdout);  // Now stdout appears
    fprintf(stderr, "Error message 3 (no fflush needed)\n");
    
    return 0;
}

默认情况下,stderr 是无缓冲的,因此通常不需要 fflush。本示例将其与缓冲的 stdout 进行对比。sleep 演示了缓冲行为。错误消息立即显示,而普通输出则等待 fflush 或换行符。这种自动行为使 stderr 非常适合错误报告。

fflush 和 Fork 安全性

学习 fflush 如何防止在分叉进程中出现重复输出。

fork_fflush.c
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("Before fork (buffered)");
    fflush(stdout);  // Clear buffer before fork
    
    pid_t pid = fork();
    if (pid == 0) {
        printf("\nChild process\n");
    } else {
        printf("\nParent process\n");
    }
    
    return 0;
}

分叉时,缓冲数据会在两个进程中复制。本示例展示了 fflush 如何通过在 fork 前清除缓冲区来防止重复输出。如果没有刷新,“Before fork”可能会显示两次。刷新后,每个进程仅打印自己的消息。此技术对于多进程编程至关重要。

fflush 的错误处理

在使用 fflush 时正确检查错误。

error_fflush.c
#include <stdio.h>
#include <errno.h>

int main() {
    FILE *fp = fopen("output.txt", "w");
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }
    
    fprintf(fp, "Important data");
    
    if (fflush(fp) == EOF) {
        perror("Failed to flush data");
        fclose(fp);
        return 1;
    }
    
    // Simulate disk full error
    // On some systems, fflush might detect write errors
    
    if (fclose(fp) == EOF) {
        perror("Failed to close file");
        return 1;
    }
    
    return 0;
}

本示例演示了 fflush 的正确错误处理。该函数在失败时返回 EOF,这可能表示磁盘已满或权限问题。始终检查此返回值以进行关键操作。请注意,某些错误可能仅在 fclose 期间检测到,因此两种检查对于健壮的文件处理都很重要。

使用 fflush 的最佳实践

来源

C fflush 文档

本教程深入探讨了 fflush 函数,从基本用法到高级场景。正确理解输出缓冲和刷新对于 C 程序中可靠的 I/O 操作至关重要。使用这些技术来确保您的程序输出在所有情况下都能按预期运行。

作者

我叫 Jan Bodnar,我是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1400 多篇文章和 8 本电子书分享我的专业知识。凭借十多年的教学经验,我努力使编程变得易于理解和引人入胜。

列表 C 标准库