バイト単位の入出力

さて、システムコールのread/writeではストリームを指し示すためにint型のファイルディスクリプタを使用しましたが、標準入出力関数ではFILE型の変数を使用します。

FILE *fopen(const char *path, const char *mode);
ファイルにつながるストリームを開く
int fclose(FILE *stream);
ストリームを閉じる

バイト単位の入出力にはfgetc/fputcを使用する。getc/putcはそのマクロ版だが速度は変わらない。getchar/putcharは入出力のストリームを標準入出力に固定したもの。ungetcは値をバッファに戻す。連続して戻すことはできない。
教科書にはcatを再実装するという課題?が載ってたけどまた同じの作るのもつまんないので、ファイルから1バイトずつ読み込みながら標準出力に書き込み、数字に遭遇したらungetcして残りを一気にダンプする、というプログラムを書きました。まあ使い道はないけど。ungetcを使いたかっただけだけど。

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

static void die( const char *s );
static void dump_stream( FILE *stream );

int
main( int argc, char *argv[] ) {
    char path[] = "./ungetc.c";
    FILE *file;
    
    file = fopen(path, "r");
    if (file == NULL) die(path);

    while (1) {
        int c = fgetc(file);
        if ( c == EOF ) break;
        if ( isdigit(c) ) {
            if ( ungetc(c, file) == EOF ) die(path);
            break;
        }
        else {
            if ( putchar(c) == EOF ) die(path);
        }
    }

    printf("?n----------?n");
    dump_stream(file);

    if (fclose(file) == EOF) die(path);

    return 0;
}

static void
dump_stream( FILE *stream ) {
    while (1) {
        int c = fgetc(stream);
        if (c == EOF) break;
        if ( putchar(c) == EOF ) die("dump");
    }
}

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

で、P112

while ((c = fgetc(f)) != EOF) {
        if (putchar(c) < 0) exit(1);
}

このwhile文の条件式はC言語ではよく使うイディオムで、EOFに当たるまでfgetc()し続けるという意味です。

と書いてあって、まあそれは見ればわかるんだけどごちゃごちゃしててどうなんかなーとか思いました。
上の例でいうとdump_stream()のwhile文がこれを1文ずつちゃんと書いたバージョンなわけですが、while文のブロック内の先頭2行が条件式の中に入るか入らないかという違いです。どーなんだろ。人それぞれってとこで落ち着くのかな。ちなみに俺の場合、昔なら条件式の中に書いてたけど今は別々に書く。でもまた変わるかも。という感じです。