C言語再入門、ふつうのLinuxプログラミング

6章:ストリームに関わるライブラリ関数

システムコールを直接使ってプログラミングすることの問題点

  • バイト単位でしか読み書きできない
  • システムコール呼び出しは関数呼び出しよりずっと遅い
  • 利便性を向上するためにstdio : standard I/O libraryが作られた。
  • stdioはlibcの中でも大部分を占める


バッファリング

  • 以下のような機能を提供する
    • 1バイト読む
    • 1バイト書く

FILE型

  • システムコールレベルでは、ストリームを指すのにファイルディスクリプタを使っていた
  • stdioでは同じような役割のためにFILEという型へのポインタを使う
  • FILE型はtypedefで定義された型で、その中にはfdとstdioバッファの内部情報が入っている。プログラマはFILE型の中身をきにせず使える。
  • fopen(3)
  • fclose(3)
    • close()に対応するAPI
    • 成功した場合は、0。失敗した場合は定数EOFを返し、原因を表す定数をerrnoにセットする。
    • EOFはstdio.hで定義されているマクロで普通は-1

バイト単位の入出力

  • fgetc(3)
    • streamから1バイト読み込んで返す
  • fputc(3)
    • streamにバイトcを書き込む
  • getc(3)
  • put(3)
    • マクロ版
  • getchar(3)
  • putchar(3)
    • 入力元、出力先が固定されているバイト単位の入出力API
  • ungetc(3)
    • バイト単位で値をバッファに戻す

文字列の入出力

fget(3)

#include

char *fgets(char *buf, int size, FILE *stream);

  • streamから1行読み込んで、第一引数のバッファbufに格納する
  • fgrets()はどんな場合でも、最大size-1バイトまでしか読まない
  • sizeバイトではなく、size-1バイトなのは、末尾に'\0'を書き込むから
  • bufのサイズをsizeに指定するのが普通の使い方
  • 正常に1行読み込むか、size-1バイト読んだ場合はbufを返す
  • 1文字も読まずにEOFにあたった場合はNULLを返す
  • 最大の問題点は、ちゃんと1行読んで止まったのか、バッファいっぱいまで書き込んで止まったのかを区別できないこと

バッファオーバーフロー

  • gets()は使っちゃいけない


fputs(3)

#include

int fputs(const char *buf, FILE *stream);

  • 文字列bufをstreamに出力する
  • 問題なく出力できた時は0以上の値を返す
  • ストリームにすべてのバイト列を書き終わったか、何か問題が起きた時はEOFを返す
  • 問題が起きた場合は原因を表す定数がerrnoにセットされるが、ストリームが終了した場合と区別するためには次のコードのように予めerrnoを0にしないといけない

#include

{
errno = 0;
if (fputs(buf, f) == EOF) {
if(errno != 0) {
/** errnoを見て判断 **/
}
}
}

備忘録
  • libc
    • 標準Cライブラリのこと。glibcgnu libc
  • typedefって