具有包含char的结构类型的out参数的公共API设计*

具有包含char的结构类型的out参数的公共API设计*,c,struct,enums,union,software-design,C,Struct,Enums,Union,Software Design,我正在为事件通知设计一个独立于公共平台的API,目前有以下接口: enum ns_event_type{ deleted, moved }; struct ns_event_meta{ enum ns_event_type type; size_t internal_buffer_size; void *internal_buffer; /* Memory to store either deleted_path or moved */ unio

我正在为事件通知设计一个独立于公共平台的API,目前有以下接口:

enum ns_event_type{
    deleted,
    moved
};

struct ns_event_meta{
    enum ns_event_type type;
    size_t internal_buffer_size;
    void *internal_buffer; /* Memory to store either deleted_path or moved */
    union {
        const char *deleted_path;
        struct {
             const char *moved_from;
             const char *moved_to;
        } moved;
    } event_data;
};

typedef struct ns_event_queue ns_event_queue;

int ns_take_event(ns_event_queue *queue, struct ns_event_meta *meta_out);
我设计
struct ns\u event\u meta的方法是包含一个原始内存缓冲区。缓冲区用作
const char*readable_path
或(
const char*moved_from
const char*moved_to
)的容器

因此,如果
void*interval\u buffer
大小不足以容纳正在执行的事件的路径,则函数
ns\u take\u event
返回
-1
,并且调用方预计会增加
void*internal\u buffer

我看到的这个设计的问题是,库的客户机可以访问原始缓冲区
void*internal_buffer
,这实际上不是客户机想要访问的。相反,事件元旨在通过成员
enum ns_event_type检查
事件数据


有没有其他方法来解决这样的设计问题?

在我看来,您有两个相互冲突的需求

  • 您希望用户为
    internal\u buffer
    分配内存(我假设还更新
    internal\u buffer\u size

  • 您想对用户隐藏
    内部\u缓冲区

  • 你不能两者都做!如果用户要处理内存分配,则不能“隐藏”缓冲区。因此,要么您必须接受用户知道缓冲区,要么您必须在代码中分配内存

    隐藏内部数据的一种众所周知的方法是使用不透明的数据类型。基本思想是在结构中收集私有数据成员,例如
    struct private
    。用户只获取指向结构的指针,而不获取有关结构内容的信息。您必须提供操作隐藏/私有数据所需的所有函数

    它可能看起来像:

    ns_event.h(由用户包含)

    ns_event.c(您的代码)

    也可以使用句柄而不是指向不透明数据类型的指针。像

    struct ns_event_meta{
        enum ns_event_type type;
        union {
            const char *deleted_path;
            struct {
                 const char *moved_from;
                 const char *moved_to;
            } moved;
        } event_data;
        int handle;    // A handle to hide the location of "private" data
                       // Translation will be needed in the c-file
    };
    
    handle
    将只是代码在
    ns\u init\u buffer
    调用中选择的整数。在您的代码中,您将有一个表,可以在句柄数和指向私有数据的指针之间进行转换。这样,用户将永远不知道私有数据存储在哪里,甚至不知道保存私有数据的结构的名称


    注意:将句柄存储在struct中是一个有趣的问题。您可以将其从结构中删除,并让init函数返回句柄。然后,用户必须将句柄存储在其他变量中,并将其作为额外的函数参数传递。

    在我看来,您有两个相互冲突的需求

  • 您希望用户为
    internal\u buffer
    分配内存(我假设还更新
    internal\u buffer\u size

  • 您想对用户隐藏
    内部\u缓冲区

  • 你不能两者都做!如果用户要处理内存分配,则不能“隐藏”缓冲区。因此,要么您必须接受用户知道缓冲区,要么您必须在代码中分配内存

    隐藏内部数据的一种众所周知的方法是使用不透明的数据类型。基本思想是在结构中收集私有数据成员,例如
    struct private
    。用户只获取指向结构的指针,而不获取有关结构内容的信息。您必须提供操作隐藏/私有数据所需的所有函数

    它可能看起来像:

    ns_event.h(由用户包含)

    ns_event.c(您的代码)

    也可以使用句柄而不是指向不透明数据类型的指针。像

    struct ns_event_meta{
        enum ns_event_type type;
        union {
            const char *deleted_path;
            struct {
                 const char *moved_from;
                 const char *moved_to;
            } moved;
        } event_data;
        int handle;    // A handle to hide the location of "private" data
                       // Translation will be needed in the c-file
    };
    
    handle
    将只是代码在
    ns\u init\u buffer
    调用中选择的整数。在您的代码中,您将有一个表,可以在句柄数和指向私有数据的指针之间进行转换。这样,用户将永远不知道私有数据存储在哪里,甚至不知道保存私有数据的结构的名称


    注意:将句柄存储在struct中是一个有趣的问题。您可以将其从结构中删除,并让init函数返回句柄。然后,用户必须将句柄存储在其他变量中,并将其作为一个额外的函数参数传递。

    ,调用者将增长void*internal\u buffer-进行不透明设计的关键在于不要让调用者触摸您的数据。在
    ns\u take\u事件中自己重新分配缓冲区。没有
    int ns\u event\u meta\u resize\u internal\u buffer(ns\u event\u meta*meta)等函数的任何原因
    枚举ns_事件类型ns_事件匹配获取事件(ns_事件meta*meta)
    ?@KamilCuk我不想让
    struct ns\u event\u meta
    不透明,因为我希望调用方能够访问成员
    event\u type
    event\u data
    。你建议把它弄得不透明吗?或者可以将
    void*
    参数添加到
    ns\u take\u event
    函数中,从而将
    内部缓冲区
    从结构成员中删除吗?我不清楚您在问什么。答案可能是:“让函数执行realloc”,但我想这不是您想要的……也许您可以将“private”成员放入不透明的数据类型中,以便用户看到的结构只包含“public”成员和指向不透明数据类型的指针。然后,您必须提供许多函数来操作不透明数据。@St.Antario是的,这是基本思想。如果要进一步“隐藏”真实数据,可以让结构包含句柄(即简单数字),而不是不透明指针。那么您的代码将需要一个表来转换为
    struct ns_event_meta{
        enum ns_event_type type;
        union {
            const char *deleted_path;
            struct {
                 const char *moved_from;
                 const char *moved_to;
            } moved;
        } event_data;
        int handle;    // A handle to hide the location of "private" data
                       // Translation will be needed in the c-file
    };