FMEMOPEN(3)

名前
fmemopen, open_memstream, open_wmemstream - メモリーをストリームとしてオープンする

書式
#include <stdio.h>
FILE *fmemopen(void *buf, size_t size, const char *mode);
FILE *open_memstream(char **ptr, size_t *sizeloc);
#include <wchar.h>
FILE *open_wmemstream(wchar_t **ptr, size_t *sizeloc);

glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):

fmemopen(), open_memstream(), open_wmemstream():
    glibc 2.10 以降:
        _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
    glibc 2.10 より前:
        _GNU_SOURCE

説明
fmemopen() 関数は、ストリームをオープンし、そのストリームに mode で指定されたアクセス許可を設定する。 そのストリームを通じて、 buf で指定された文字列やメモリーバッファーへの読み書きができる。 このバッファーは少なくとも size バイトの長さでなければならない。

引き数 mode は fopen(3) の場合と同じである。 mode で追記モード (append mode) が指定された場合、ファイル位置の初期値は バッファー中の 最初のヌルバイト ('\0') の位置に設定される。 それ以外の場合は、ファイル位置の初期値はバッファーの先頭になる。 glibc 2.9 以降では、文字 'b' を mode の二番目の文字として指定 することができる。 この文字は「バイナリ」モードを指定するものである。 このモードでは、書き込み時に文字列終端のヌルバイトが黙って追加 される ことはない。また、 fseek(3) SEEK_END は、文字列の長さからの相対値 ではなく、バッファーの末尾 (size で指定した値) からの相対値となる。

書き込み用にオープンされたストリームをフラッシュ (fflush(3)) やクローズ (fclose(3)) した時に、 (バッファーに空きがあれば) ヌルバイトがバッファーの末尾に書き込まれる。 このようにするためには、呼び出し元は バッファーに 1バイト余裕を作る (size にこの 1バイトを含めた値を指定する) 必要がある。 バッファーに size バイトよりたくさん書き込もうとした場合には、エラーとなる。 (デフォルトでは、このようなエラーが見えるのは stdio バッファーがフラッシュされた時だけである。 以下の呼び出しを使ってバッファーリングを無効にする方法は、 出力操作を行った時点でエラーを検出するのに役立つ。
    setbuf(stdream, NULL); 別の方法としては、 以下のように、 呼び出し側が明示的に stdio ストリームバッファーとして buf を指定し、バッファーの指定時にバッファーのサイズを stdio に教える方法がある。
    setbuffer(stream, buf, size);

読み出し用にオープンされたストリームでは、 バッファー内にヌルバイト ('\0') があっても 読み出し操作がファイル末尾 (end-of-file) を返すことはない。 バッファーからの読み出しでファイル末尾が返るのは、 ファイルポインターがバッファーの先頭から size バイトを越えて先に進もうとした場合だけである。

buf に NULL が指定された場合、 fmemopen() は動的に size バイトの長さのバッファーを確保する。 この方法は、一時バッファーにデータの書き込みを行ってから、 その内容を再度読み出すようなアプリケーションで有用である。 このバッファーはストリームがクローズされるときに自動的に解放される。 呼び出し元からはこの関数が割り当てた一時バッファーへのポインター値を 知る方法は存在しない点に注意 (下記の open_memstream() も参照)。 open_memstream() 関数は、バッファーへの書き込み用にストリームをオープンする。 バッファーは (malloc(3) を使って) 動的に割り当てられ、必要に応じて自動的に伸長する。 ストリームをクローズした後で、呼び出し元はこのバッファーを free(3) すべきである。 このストリームが クローズ (fclose(3)) されたりフラッシュ (fflush(3)) された時に、 ptr と sizeloc の値はそれぞれバッファーへのポインターとそのサイズに更新される。 これらの値は、呼び出し元がそのストリームに新たな書き込みを 行わない場合に限り有効である。 ストリームに書き込みを行った際には、これらの変数を参照する前に ストリームを再度フラッシュしなければならない。 バッファー末尾のヌルバイトは保持される。 このヌルバイトは sizeloc に格納されるサイズには「含まれない」。 ストリームのファイル位置は fseek(3) や fseeko(3) で変更できる。 すでにデータが書き込まれた領域の末尾より先にファイル位置を動かすと、 その間の領域は 0 で埋められる。 open_wmemstream() は open_memstream() と同様だが、バイトではなくワイド文字に対して操作を行う点が異なる。

返り値
成功して終了した場合には、 fmemopen(), open_memstream(), open_wmemstream() は FILE ポインターを返す。 失敗した場合は、 NULL を返し、 errno にエラーを示す値をセットする。

バージョン
fmemopen() と open_memstream() は glibc 1.0.x ですでに利用可能であった。 open_wmemstream() は glibc 2.4 以降で利用可能である。

準拠
POSIX.1-2008. これらの関数は POSIX.1-2001 では規定れていないが、 Linux 以外のシステムで広く利用可能である。 POSIX.1-2008 では mode の 'b' は無視されるべきだと規定されて いる。一方、Technical Corrigendum (正誤表) 1 では、mode の 'b' が指定された場合の扱いは実装依存であることを許容するように 標準規格が修正されており、glibc の 'b' の扱いは許されている。

注意
これらの関数が返すファイルストリームに対応するファイル ディスクリプターはない (つまり、返されたストリームに対して fileno(3) を呼び出すとエラーが返ることになる)。

バグ
バージョン 2.7 より前の glibc では、 open_memstream() で作成されたストリームの末尾より先にファイル位置を動かしても、 バッファーが伸長されず、 fseek(3) が失敗し -1 が返る。 size に 0 が指定された場合、 fmemopen() はエラー EINVAL で失敗 する。この場合にはストリームの作成に成功して、最初の読み出しを行った際に EOF (end of file) が返される方が、ストリームの扱いの一貫性が増すだろう。 また、 POSIX.1-2008 ではこの場合のエラーは規定されていない。 fmemopen() に追記モード ("a" や "a+") を指定すると、 ファイル位置の初期値は最初のヌルバイトに設定されるが、(ファイル オフセットをストリームの末尾以外の位置に再設定した場合)それ以降の 書き込みではストリームの末尾への追記が行われる訳ではない。 fmemopen() の mode 引き数に追記モード ("a" や "a+") を指定し、 size 引き数で指定した範囲の buf 内にヌルバイトがない場合、 POSIX.1-2008 では、ファイル位置の初期値はバッファーの末尾の直後の バイトに設定すべきとされている。しかし、glibc の fmemopen() では この場合ファイル位置は -1 に設定される。 fmemopen() でバイナリモードを指定するには、 'b' は mode の 2 文字目 でなければならない。 例えば、 "wb+" は意図通りの効果になるが、 "w+b" はそうではない。 これは fopen(3) の mode の扱いとは異なる。 glibc 2.9 での fmemopen() の「バイナリ」モードの追加は、 ABI (Application Binary Interface) が黙って変更された。 それ以前の fmemopen() では mode 内の 'b' は無視されていた。

例
このプログラムは fmemopen() を使って出力バッファーをオープンし、 open_memstream() を使って動的にサイズが変化する出力バッファーをオープンしている。 (プログラムの第一コマンドライン引き数から取った) 入力文字列を スキャンして整数を読み込み、これらの整数の二乗を出力バッファーに書き出す。 このプログラムの実行例は以下のようになる。
$ ./a.out '1 23 43'
size=11; ptr=1 529 1849

  プログラムのソース
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
    FILE *out, *in;
    int v, s;
    size_t size;
    char *ptr;
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <file>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    in = fmemopen(argv[1], strlen(argv[1]), "r");
    if (in == NULL)
        handle_error("fmemopen");
    out = open_memstream(&ptr, &size);
    if (out == NULL)
        handle_error("open_memstream");
    for (;;) {
        s = fscanf(in, "%d", &v);
        if (s <= 0)
            break;
        s = fprintf(out, "%d ", v * v);
        if (s == -1)
            handle_error("fprintf");
    }
    fclose(in);
    fclose(out);
    printf("size=%zu; ptr=%s\n", size, ptr);
    free(ptr);
    exit(EXIT_SUCCESS);
}

関連項目
fopen(3), fopencookie(3)

この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。