FMEMOPEN - Linux手册页

时间:2019-08-20 18:00:20  来源:igfitidea点击:

Linux程序员手册 第3部分
更新日期: 2020-04-11

名称

fmemopen-以流形式打开内存

语法

#include <stdio.h>

FILE *fmemopen(void *buf, size_t size, const char *mode);

glibc的功能测试宏要求(请参阅feature_test_macros(7)):

fmemopen():

Since glibc 2.10:
_POSIX_C_SOURCE>= 200809L
Before glibc 2.10:
_GNU_SOURCE

说明

fmemopen()函数打开一个流,该流允许通过mode指定的访问。该流允许对buf指向的字符串或内存缓冲区执行I / O。

mode参数指定流上I / O的语义,并且为以下之一:

r
流将打开以供阅读。
w
流将打开以进行写入。
a
附加;打开流进行写入,并将初始缓冲区位置设置为第一个空字节。
r+
打开流以进行读写。
w+
打开流以进行读写。缓冲区内容被截断(即aq \ 0aq放在缓冲区的第一个字节中)。
a+
附加;打开流以进行读取和写入,并将初始缓冲区位置设置为第一个空字节。

流保持当前位置的概念,即当前位置,即执行下一个I / O操作的位置。当前位置由I / O操作隐式更新。可以使用fseek(3)显式更新它,并使用ftell(3)确定它。在除附加模式以外的所有模式下,初始位置均设置为缓冲区的开始。在追加模式下,如果在缓冲区中未找到空字节,则初始位置为size + 1。

如果将buf指定为NULL,则fmemopen()会分配一个大小为字节的缓冲区。这对于希望将数据写入临时缓冲区然后再次读取的应用程序很有用。初始位置设置为缓冲区的开始。当关闭流时,缓冲区自动释放。请注意,调用者无法获取指向此调用分配的临时缓冲区的指针(但请参见open_memstream(3))。

如果buf不为NULL,则它应指向调用方分配的至少len个字节的缓冲区。

当已打开要写入的流被刷新(fflush(3))或关闭(fclose(3))时,如果有空间,则在缓冲区的末尾写入一个空字节。调用者应确保缓冲区中有一个额外的字节(并且大小计入该字节)以允许此操作。

在为读取而打开的流中,缓冲区中的空字节(aq \ 0aq)不会导致读取操作返回文件结束指示。仅当当前缓冲区位置将大小字节提前到缓冲区的开头时,才从缓冲区进行读取将指示文件结束。

写操作发生在当前位置(对于附加模式除外),或在流的当前大小处(对于附加模式)。

尝试将超过大小字节的内容写入缓冲区会导致错误。默认情况下,此类错误仅在刷新stdio缓冲区时才可见(由于没有数据)。通过以下调用禁用缓冲可能对检测输出操作时的错误很有用:

setbuf(stream,NULL);

返回值

成功完成后,fmemopen()返回FILE指针。否则,将返回NULL并将errno设置为指示错误。

版本

fmemopen()在glibc 1.0.x中已经可用。

属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
fmemopen(),Thread safetyMT-Safe

遵循规范

POSIX.1-2008。 POSIX.1-2001中未指定此功能,并且在其他系统上未广泛使用。

POSIX.1-2008指定应忽略模式下的aqbaq。但是,技术勘误1调整了标准,以允许对此情况进行特定于实现的处理,从而允许对aqbaq进行glibc处理。

备注

没有与此函数返回的文件流关联的文件描述符(即,如果在返回的流上调用fileno(3)将返回错误)。

在2.22版中,删除了二进制模式(请参见下文),修复了fmemopen()实现中的许多长期存在的错误,并为此接口创建了新的版本化符号。

Binary mode

从2.9版到2.21版,fmemopen()的glibc实现支持"二进制"模式,通过将字母aqbaq指定为mode中的第二个字符来启用该模式。在这种模式下,写操作不会隐式添加一个终止的空字节,并且fseek(3)SEEK_END相对于缓冲区的末尾(即size参数指定的值)而不是当前字符串的长度。

一个API错误困扰着二进制模式的实现:要指定二进制模式,aqbaq必须是模式中的第二个字符。因此,例如," wb +"具有期望的效果,但是" w + b"没有。这与fopen(3)对mode的处理不一致。

在glibc 2.22中删除了二进制模式;在mode中指定的aqbaq无效。

BUGS

在2.22之前的glibc版本中,如果将size指定为零,则fmemopen()失败,错误为EINVAL。如果这种情况下成功创建了一个流,然后在第一次读取尝试时返回了文件末尾,那将会更加一致。从2.22版开始,glibc实现提供了该行为。

在2.22之前的glibc版本中,为fmemopen()指定附加模式(" a"或" a +")可将初始缓冲区位置设置为第一个空字节,但是(如果当前位置被重置为非末尾位置)流)不会强制随后的写入追加到流的末尾。此错误已在glibc 2.22中修复。

在2.22之前的glibc版本中,如果fmemopen()的mode参数指定了append(" a"或" a +"),并且size参数未覆盖buf中的空字节,那么根据POSIX.1-2008,初始缓冲区位置应设置为缓冲区结束后的下一个字节。但是,在这种情况下,glibc fmemopen()会将缓冲区位置设置为-1。此错误已在glibc 2.22中修复。

在2.22之前的glibc版本中,当对由fmemopen()创建的流执行以SEEK_END的ncece值调用fseek(3)时,将从流的末尾位置减去偏移量,而不是相加。此错误已在glibc 2.22中修复。

glibc 2.9为fmemopen()添加了"二进制"模式,无声地更改了ABI:以前,fmemopen()在模式下忽略了aqbaq。

示例

下面的程序使用fmemopen()打开输入缓冲区,并使用open_memstream(3)打开动态大小的输出缓冲区。程序扫描其输入字符串(从程序的第一个命令行参数获取)以读取整数,并将这些整数的平方写入输出缓冲区。该程序产生的输出示例如下:

$ ./a.out aq1 23 43aq
size=11; ptr=1 529 1849

Program source

#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 aq<num>...aq\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),open_memstream(3)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/