具有包含char的结构类型的out参数的公共API设计*
我正在为事件通知设计一个独立于公共平台的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
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
};