ZetCode

C setvbuf function

last modified April 6, 2025

I/O buffering is a crucial performance optimization in C programming. The setvbuf function allows fine-grained control over stream buffering behavior. This tutorial explains setvbuf in detail, covering buffer types, usage patterns, and practical examples. Mastering buffering techniques can significantly improve your program's I/O efficiency and responsiveness.

What Is setvbuf?

The setvbuf function controls buffering for a file stream. It takes a stream pointer, buffer, mode, and size as parameters. Buffering modes include fully buffered, line buffered, and unbuffered. The function must be called after opening the stream but before any I/O operations. It returns zero on success and non-zero on failure.

Basic Syntax

The function prototype for setvbuf is:

int setvbuf(FILE *stream, char *buffer, int mode, size_t size);

The mode parameter can be _IOFBF (full buffering), _IOLBF (line buffering), or _IONBF (no buffering). The buffer can be NULL to let the function allocate its own buffer. The size specifies the buffer size in bytes.

Full Buffering Example

This example demonstrates full buffering with a custom buffer.

full_buffering.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("output.txt", "w");
    char buffer[1024];  // 1KB buffer
    
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }
    
    // Set full buffering with our 1KB buffer
    if (setvbuf(fp, buffer, _IOFBF, sizeof(buffer)) != 0) {
        perror("Failed to set buffer");
        fclose(fp);
        return 1;
    }
    
    // Write data - will be buffered
    for (int i = 0; i < 100; i++) {
        fprintf(fp, "Line %d\n", i);
    }
    
    fclose(fp);
    return 0;
}

Here we create a 1KB buffer and set full buffering mode (_IOFBF). The output is collected in the buffer until it fills or the stream is closed. This reduces disk I/O operations for better performance with large writes.

Line Buffering Example

Line buffering flushes the buffer when a newline is encountered.

line_buffering.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("lines.txt", "w");
    
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }
    
    // Set line buffering with automatic buffer
    if (setvbuf(fp, NULL, _IOLBF, BUFSIZ) != 0) {
        perror("Failed to set buffer");
        fclose(fp);
        return 1;
    }
    
    // Each line will be written immediately
    fprintf(fp, "First line\n");
    fprintf(fp, "Second line\n");
    fprintf(fp, "Third line\n");
    
    fclose(fp);
    return 0;
}

With line buffering (_IOLBF), each line is written to the file when a newline is encountered. This is useful for interactive programs where you want output to appear immediately. We let setvbuf allocate its own buffer by passing NULL.

No Buffering Example

Disabling buffering causes immediate writes to the output device.

no_buffering.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("immediate.txt", "w");
    
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }
    
    // Disable buffering
    if (setvbuf(fp, NULL, _IONBF, 0) != 0) {
        perror("Failed to set buffer");
        fclose(fp);
        return 1;
    }
    
    // Each character is written immediately
    for (char c = 'A'; c <= 'Z'; c++) {
        fputc(c, fp);
    }
    
    fclose(fp);
    return 0;
}

Unbuffered mode (_IONBF) causes each I/O operation to be performed immediately. This is useful for critical messages or when you need real-time output. The buffer and size parameters are ignored in this mode.

Changing stdout Buffering

You can modify the buffering behavior of standard output.

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

int main() {
    // Change stdout to line buffered
    setvbuf(stdout, NULL, _IOLBF, 0);
    
    printf("This will appear immediately");
    sleep(2);
    printf(" when the line is complete.\n");
    
    // Now change to unbuffered
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("This appears immediately");
    sleep(2);
    printf(" even without newline.\n");
    
    return 0;
}

This example shows how to change stdout's buffering behavior. Initially set to line buffering, the first message appears only after the newline. After switching to unbuffered mode, output appears immediately. This is useful for real-time status updates.

Automatic Buffer Allocation

Let setvbuf handle buffer allocation by passing NULL.

auto_buffer.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("auto.txt", "w");
    
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }
    
    // Let setvbuf allocate its own buffer
    if (setvbuf(fp, NULL, _IOFBF, 4096) != 0) {
        perror("Failed to set buffer");
        fclose(fp);
        return 1;
    }
    
    // Write data using the automatically allocated buffer
    for (int i = 0; i < 1000; i++) {
        fprintf(fp, "Record %d\n", i);
    }
    
    fclose(fp);
    return 0;
}

By passing NULL as the buffer pointer, we let setvbuf allocate its own 4KB buffer. This is often simpler than managing your own buffer memory. The buffer is automatically freed when the stream is closed.

Error Handling

Proper error handling ensures your program behaves predictably.

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

int main() {
    FILE *fp = fopen("test.txt", "w");
    char *buffer = malloc(2048);
    
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }
    
    if (buffer == NULL) {
        perror("Failed to allocate buffer");
        fclose(fp);
        return 1;
    }
    
    // Try to set buffer
    if (setvbuf(fp, buffer, _IOFBF, 2048) != 0) {
        perror("Failed to set buffer");
        free(buffer);
        fclose(fp);
        return 1;
    }
    
    // Use the buffered stream
    fprintf(fp, "Testing buffered output\n");
    
    // Clean up
    free(buffer);
    fclose(fp);
    return 0;
}

This example demonstrates comprehensive error handling. We check for file opening errors, buffer allocation failures, and setvbuf errors. Resources are properly freed in all error paths. Robust error handling prevents memory leaks and undefined behavior.

Timing Buffered vs Unbuffered

Compare performance between buffered and unbuffered I/O.

timing.c
#include <stdio.h>
#include <time.h>

#define ITERATIONS 100000

void test_buffered() {
    FILE *fp = fopen("buffered.txt", "w");
    setvbuf(fp, NULL, _IOFBF, BUFSIZ);
    
    clock_t start = clock();
    for (int i = 0; i < ITERATIONS; i++) {
        fprintf(fp, "Line %d\n", i);
    }
    clock_t end = clock();
    fclose(fp);
    
    printf("Buffered: %.2f seconds\n", 
           (double)(end - start) / CLOCKS_PER_SEC);
}

void test_unbuffered() {
    FILE *fp = fopen("unbuffered.txt", "w");
    setvbuf(fp, NULL, _IONBF, 0);
    
    clock_t start = clock();
    for (int i = 0; i < ITERATIONS; i++) {
        fprintf(fp, "Line %d\n", i);
    }
    clock_t end = clock();
    fclose(fp);
    
    printf("Unbuffered: %.2f seconds\n", 
           (double)(end - start) / CLOCKS_PER_SEC);
}

int main() {
    test_buffered();
    test_unbuffered();
    return 0;
}

This benchmark compares buffered and unbuffered write performance. Buffered I/O is typically much faster as it minimizes system calls. The difference becomes more pronounced with larger amounts of data. Always consider buffering for performance-critical I/O operations.

Best Practices for Using setvbuf

Source

C setvbuf Documentation

This tutorial has explored the powerful setvbuf function for controlling I/O buffering in C. Proper buffering can dramatically improve your program's I/O performance and responsiveness in various scenarios.

Author

My name is Jan Bodnar, and I'm a dedicated programmer with a deep passion for coding. Since 2007, I've been sharing my expertise through over 1,400 articles and 8 e-books. With more than a decade of teaching experience, I strive to make programming accessible and engaging.

List C Standard Library.