微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从内部函数不是文件创建一个`FILE`?

如何解决从内部函数不是文件创建一个`FILE`?

POSIX/C 定义了许多很好的函数来处理文件对象,例如 fputsfprintf

/*
`FILE*` rather than `SomeType*` wanted?
*/
void f(const char *text) {
    SomeType* printer_object = \
                  allocate_printer_if_not_defined_statically_else_return_that();

    printer_object.error_out(text);   /* equiv. semantics to stderr */
    // printer_object.info_out(text); /* equiv. semantics to stdout */
    
    cleanup_printer_object(&printer_object);
}

如何启用随机函数(如上面的 f)以符合 fopenfclose 等?


部分解决方案(感谢 Freenode 的 ##C 上的 atk):

#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#define container_of(ptr,type,member) ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type,member)))

struct io_ops;

typedef size_t io_ops_read_func(struct io_ops **ops,void *buf,size_t size);
typedef size_t io_ops_write_func(struct io_ops **ops,const void *buf,size_t size);
typedef void io_ops_close_func(struct io_ops **ops);

struct io_ops {
    io_ops_read_func *read;
    io_ops_write_func *write;
    io_ops_close_func *close;
    /* You also probably want seek */
};

size_t io_read(struct io_ops **ops,size_t size)
{
    if (!ops || !*ops) {
        errno = EINVAL;
        return 0;
    }
    if (!(*ops)->read) {
        errno = ENOSYS;
        return 0;
    }

    return (*ops)->read(ops,buf,size);
}

size_t io_write(struct io_ops **ops,size_t size)
{
    if (!ops || !*ops) {
        errno = EINVAL;
        return 0;
    }
    if (!(*ops)->write) {
        errno = ENOSYS;
        return 0;
    }

    return (*ops)->write(ops,size);
}

void io_close(struct io_ops **ops)
{
    if (!ops || !*ops) {
        errno = EINVAL;
        return;
    }
    if (!(*ops)->close) {
        errno = ENOSYS;
        return;
    }

    (*ops)->close(ops);
}

struct buffer_io {
    void *buffer;
    size_t size;
    size_t pos;
    struct io_ops *ops;
};

size_t buffer_io_ops_read(struct io_ops **ops,size_t size)
{
    struct buffer_io *bio = container_of(ops,struct buffer_io,ops);

    assert(bio->pos <= bio->size);

    if (size > bio->size - bio->pos)
        size = bio->size - bio->pos;

    memcpy(buf,(unsigned char *)bio->buffer + bio->pos,size);
    bio->pos += size;

    return size;
}

size_t buffer_io_ops_write(struct io_ops **ops,ops);

    assert(bio->pos <= bio->size);

    if (size > bio->size - bio->pos)
        size = bio->size - bio->pos;
    memcpy((unsigned char *)bio->buffer + bio->pos,size);
    bio->pos += size;

    return size;
}

void buffer_io_ops_close(struct io_ops **ops)
{
    struct buffer_io *bio = container_of(ops,ops);

    free(bio);
}

struct io_ops buffer_io_ops = {
    .read = buffer_io_ops_read,.write = buffer_io_ops_write,.close = buffer_io_ops_close,};

struct io_ops **new_buffer_io(void *buf,size_t size)
{
    struct buffer_io *bio;
    
    bio = malloc(sizeof *bio);
    if (bio == NULL)
        return NULL;

    bio->buffer = buf;
    bio->size = size;
    bio->pos = 0;
    bio->ops = &buffer_io_ops;

    return &bio->ops;
}

int main(void)
{
    char buf[1024],*test = "foo bar baz",readbuf[1024];

    struct io_ops **bio = new_buffer_io(buf,sizeof buf);

    io_write(bio,test,sizeof *test);
    io_close(bio);

    bio = new_buffer_io(buf,sizeof buf);

    io_read(bio,readbuf,sizeof *test);
    assert(memcmp(test,sizeof *test) == 0);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。