kenkovlog

けんこふたんっオフィシャユブヨグッ
アンッ!アンッ!アンッ!アンッ!

stdio.h のバッファリングを確かめる

man stdio.h に書いてある通り、stdio.h は standard buffered input/output なので、入出力をバッファリングしています。 それを確かめるための実験。

バッファリングしないコード

システムコール(open, read, write, close) を使う。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

static void do_cat(const char *path);
static void f_do_cat(const int fd);
static void die(const char *s);

int main(int argc, char *argv[]) {
    int i;
    if (argc == 1) {
        f_do_cat(0);
    } else {
        for (i = 1; i < argc; i++)
            do_cat(argv[i]);
    }
    return 0;
}

static void do_cat(const char *path) {
    int fd;
    // open a file
    fd = open(path, O_RDONLY);
    if (fd < 0) die(path);
    f_do_cat(fd);
}

#define BUF_SIZE 2048

static void f_do_cat(const int fd) {
    unsigned char buf[BUF_SIZE];
    ssize_t wc;
    while(1) {
        wc = read(fd, buf, sizeof buf);
        if (wc < 0) die("");
        else if (wc == 0) break;
        else {
            write(1, buf, wc);
        }
    }
}

static void die(const char *s) {
    perror(s);
    exit(1);
}

strace で4001B のテキストファイルを引数にしてみると

kenkov@uiharu ~/test % strace -e read,write,close,open ./a.out testfile > /dev/null
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \33\2\0\0\0\0\0"..., 832) = 832
close(3)                                = 0
open("testfile", O_RDONLY)              = 3
read(3, "11111111111111111111111111111111"..., 2048) = 2048
write(1, "11111111111111111111111111111111"..., 2048) = 2048
read(3, "11111111111111111111111111111111"..., 2048) = 1953
write(1, "11111111111111111111111111111111"..., 1953) = 1953
read(3, "", 2048)                       = 0
+++ exited with 0 +++

read, write が二回呼ばれているのがわかる。(つまりバッファリングされていない)

バッファリングしたもの

stdio.h の入出力関数(fopen, fputc, fgetc, fclose) を使う

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

static void do_cat(const char *path);
static void f_do_cat(FILE *fd);

int main(int argc, char *argv[]) {
    int i;
    if (argc == 1) {
        f_do_cat(stdin);
    } else {
        for (i = 1; i < argc; i++)
            do_cat(argv[i]);
    }
    return 0;
}

static void do_cat(const char *path) {
    FILE *fd;
    // open a file
    fd = fopen(path, "r");
    if (fd == NULL) {
        perror(path);
        exit(1);
    }
    f_do_cat(fd);
}

static void f_do_cat(FILE *fd) {
    int c;
    while ((c = fgetc(fd)) != EOF) {
        if (fputc(c, stdout) == EOF) {
            exit(1);
        }
    }
}

またまたstrace で同じファイルを引数にして使ってみると

nkov@uiharu ~/test % strace -e read,write,close,open ./b.out testfile > /dev/null
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
close(3)                                = 0
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \33\2\0\0\0\0\0"..., 832) = 832
close(3)                                = 0
open("testfile", O_RDONLY)              = 3
read(3, "11111111111111111111111111111111"..., 4096) = 4001
read(3, "", 4096)                       = 0
write(1, "11111111111111111111111111111111"..., 4001) = 4001
+++ exited with 0 +++

read, write が一回しか呼ばれていないので、バッファリングされていることがわかる。(もしバッファリングされていないとすれば、 4001 回fread, write が行われることになる)

けんこふたん