演習8-2 K&R プログラミング言語C
2010年03月20日
演習8-2
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #define MY_NULL 0 #define MY_EOF (-1) #define MY_BUFSIZ 1024 #define MY_OPEN_MAX 20 /* 一時に開けるファイルの最大数 */ /* フラグのビットフィールド */ struct flags { unsigned int is_read : 1; unsigned int is_write : 1; unsigned int is_unbuf : 1; unsigned int is_eof : 1; unsigned int is_err : 1; }; typedef struct _iobuf { int cnt; /* 残っている文字数 */ char *ptr; /* 次の文字位置 */ char *base; /* バッファの位置 */ struct flags flag; /* ファイル・アクセスのモード */ int fd; /* ファイル記述子 */ } MY_FILE; extern MY_FILE _iob[MY_OPEN_MAX]; #define my_stdin (&_iob[0]) #define my_stdout (&_iob[1]) #define my_stderr (&_iob[2]) int _fillbuf(MY_FILE *); int _flushbuf(int, MY_FILE *); #define feof(p) ((p)->flag.is_eof == 1) #define ferror(p) ((p)->flag.is_err == 1) #define fileno(p) ((p)->fd) #define my_getc(p) (--(p)->cnt >= 0 \ ? (unsigned char) *(p)->ptr++ : _fillbuf(p)) #define my_putc(x, p) (--(p)->cnt >= 0 \ ? *(p)->ptr++ = (x) : _flushbuf((x), p)) #define my_getchar() my_getc(my_stdin) #define my_putchar(x) my_putc((x), my_stdout) MY_FILE _iob[MY_OPEN_MAX] = { /* my_stdin, my_stdout, my_stderr: */ { 0, (char *) 0, (char *) 0, {1, 0, 0, 0, 0}, 0 }, { 0, (char *) 0, (char *) 0, {0, 1, 0, 0, 0}, 1 }, { 0, (char *) 0, (char *) 0, {0, 1, 1, 0, 0}, 2 } }; MY_FILE *my_fopen(char*, char*); int main(int argc, char *argv[]) { int c; char mode = 'r'; MY_FILE *fp; if (argc == 2) { if ((fp = my_fopen(argv[1], &mode)) == MY_NULL) { fprintf(stderr, "can't open %s\n", argv[1]); exit(EXIT_FAILURE); } while ((c = my_getc(fp)) != MY_EOF) { printf("%c", c); } } return 0; } #define PERMS 0666 /* 所有者、グループ、他人に対して RW */ /* my_fopen : ファイルを開いて、ファイル・ポインタを返す */ MY_FILE *my_fopen(char *name, char *mode) { int fd; MY_FILE *fp; if (*mode != 'r' && *mode != 'w' && *mode != 'a') { return MY_NULL; } for (fp = _iob; fp < _iob + MY_OPEN_MAX; fp++) { if ((fp->flag.is_read == 0 && fp->flag.is_write == 0)) { break; /* found free slot */ } } if (fp >= _iob + MY_OPEN_MAX) { /* 空きスロットなし */ return MY_NULL; } if (*mode == 'w') { fd = creat(name, PERMS); } else if (*mode == 'a') { if ((fd = open(name, O_WRONLY, 0)) == -1) { fd = creat(name, PERMS); } lseek(fd, 0L, 2); } else { fd = open(name, O_RDONLY, 0); } if (fd == -1) { /* 名前がアクセス不能 */ return MY_NULL; } fp->fd = fd; fp->cnt = 0; fp->base = MY_NULL; if (*mode == 'r') { fp->flag.is_read = 1; fp->flag.is_write = 0; } else { fp->flag.is_read = 0; fp->flag.is_write = 1; } return fp; } /* _fillbuf : 入力バッファを割り当てて、詰める */ int _fillbuf(MY_FILE *fp) { int bufsize; if (!fp->flag.is_read && fp->flag.is_eof && fp->flag.is_err) { return MY_EOF; } bufsize = fp->flag.is_unbuf ? 1 : MY_BUFSIZ; if (fp->base == MY_NULL) { /* バッファがまだない */ if ((fp->base = (char *) malloc(bufsize)) == MY_NULL) { return MY_EOF; /* バッファがとれない */ } } fp->ptr = fp->base; fp->cnt = read(fp->fd, fp->ptr, bufsize); if (--fp->cnt < 0) { if (fp->cnt == -1) { fp->flag.is_eof = 1; } else { fp->flag.is_err = 1; } fp->cnt = 0; return MY_EOF; } return (unsigned char) *fp->ptr++; }
実行結果
ビット演算を使っている版のプログラム fopen
と、ビットフィールドを使った版のプログラム fopen2
とで比較してみる。
$ time ./fopen /var/log/system.log >/dev/null real 0m0.332s user 0m0.292s sys 0m0.039s $ time ./fopen2 /var/log/system.log >/dev/null real 0m0.330s user 0m0.290s sys 0m0.039s
プログラミング言語C 第2版 ANSI規格準拠
posted with amazlet at 09.11.27
B.W. カーニハン D.M. リッチー
共立出版
売り上げランキング: 9726
共立出版
売り上げランキング: 9726