我正在评估一个库,其公共API当前如下所示:
libengine.h
/* Handle, used for all APIs */ typedef size_t enh; /* Create new engine instance; result returned in handle */ int en_open(int mode, enh *handle); /* Start an engine */ int en_start(enh handle); /* Add a new hook to the engine; hook handle returned in h2 */ int en_add_hook(enh handle, int hooknum, enh *h2);
请注意,这enh
是一个通用句柄,用作几种不同数据类型(engine和hooks)的句柄。
在内部,大多数这些API当然都将“句柄”转换为它们已经实现的内部结构malloc
:
引擎
struct engine { // ... implementation details ... }; int en_open(int mode, *enh handle) { struct engine *en; en = malloc(sizeof(*en)); if (!en) return -1; // ...initialization... *handle = (enh)en; return 0; } int en_start(enh handle) { struct engine *en = (struct engine*)handle; return en->start(en); }
就我个人而言,我讨厌将东西隐藏在typedef
s 后面,尤其是当它危及类型安全性时。(鉴于enh
,我怎么知道它实际上指的是什么?)
因此,我提交了一个拉取请求,建议进行以下API更改(在修改整个库以使其符合之后):
libengine.h
struct engine; /* Forward declaration */
typedef size_t hook_h; /* Still a handle, for other reasons */
/* Create new engine instance, result returned in en */
int en_open(int mode, struct engine **en);
/* Start an engine */
int en_start(struct engine *en);
/* Add a new hook to the engine; hook handle returned in hh */
int en_add_hook(struct engine *en, int hooknum, hook_h *hh);
当然,这使内部API实现看起来好很多,消除了强制转换,并从/从消费者的角度维护了类型安全。
libengine.c
struct engine
{
// ... implementation details ...
};
int en_open(int mode, struct engine **en)
{
struct engine *_e;
_e = malloc(sizeof(*_e));
if (!_e)
return -1;
// ...initialization...
*en = _e;
return 0;
}
int en_start(struct engine *en)
{
return en->start(en);
}
我之所以喜欢这样做,原因如下:
但是,该项目的所有者在请求请求时拒绝了(解释为):
我个人不喜欢暴露的想法
struct engine
。我仍然认为目前的方式更清洁,更友好。最初,我为钩子句柄使用了另一种数据类型,但是后来决定切换为use
enh
,因此所有类型的句柄都共享相同的数据类型以使其简单。如果这令人困惑,我们当然可以使用其他数据类型。让我们看看其他人对此PR的看法。
该库目前处于私有Beta阶段,因此不需要担心任何消费者代码。另外,我对名称有些混淆。
不透明的句柄如何比命名的不透明结构更好?
注意:我在Code Review上关闭了该问题。