C - 在库的 public 头文件中公开第三方数据结构

C - Exposing 3rd party data structures in a library's public header file

我正在编写一个包含 REST API 的库,并且表示某些数据需要使用 C 标准库中不可用的数据结构,例如哈希映射,因此我在内部使用用于实现的第 3 方库。现在我想在响应结构中公开它们,我想出了几个解决方案:

  1. 只需按原样公开类型并添加对第 3 方库的依赖并让用户调用适当的 API 函数(例如 hashmap_lib_get(users, "key") 以获取值):
// header.h (Include guards excluded)
#include <hashmap_lib.h>

struct api_response {
    int field1;
    char *field2;
    HASHMAP_LIB_HM *users; // Map of users to their email. (example)
};

问题:需要额外的用户干预,如果库是使用通用宏实现的,问题就更多了。

  1. 将类型公开为结构内部的 void 指针,并为所有适当的函数编写重复的包装器:
// header.h
struct api_response {
    int field1;
    char *field2;
    void *users; // Don't touch
};

char *api_hashmap_get(void *hm, const char *key);

api_hashmap_get 的内部实现就是 return hashmap_lib_get((HASHMAP_LIB_HM *) hm, key);

问题:需要重复各种函数定义并需要使用 void 指针。

图书馆通常是如何解决这个问题的?如果两个库彼此“相关”(例如,使用诸如 libevent 之类的事件系统来处理用户的应用程序),第一个解决方案将是有意义的,但在这种情况下,它只是关于通用数据结构,所以它对我来说没有意义,因为用户也会将其他库用于相同类型的数据结构。

我会以不同的方式描述优缺点。:

  • 选项 1 将 third-party 库的 API 合并到您自己的库中。出于技术和法律原因需要谨慎处理。

    • 在技术方面,你使你对 third-party 库的依赖更难打破。
    • 此外,您将 API 绑定到 third-party 库的特定版本或版本范围。解决这个问题的最好方法可能是向供应商提供其他库的副本,但这会带来自己的问题。
    • 在法律方面,可能会对您的图书馆的许可产生影响,具体取决于 third-party 库的许可。例如,如果 3p 库是根据 LGPL 许可的,那么仅动态链接到它并不需要您的库根据 GPL-compatible 许可获得许可,而是将其部分或全部 API 合并到您的自己可能确实引入了这样的要求。
  • 选项 2 涉及提供您自己的 API 用于操作 third-party 数据结构,并要求您放弃一些类型安全.另一方面,它将您的用户与 3p 库隔离开来。

您在评论中留言

I'd like sugestions about improving upon option 2 since it feels too verbose.

,但如果您不打算让用户通过他们的本地方式访问 third-party 数据结构,那么您别无选择,只能提供您自己的方式。如果你想将你的客户与 third-party 库隔离,那么它必须表现为包装函数。但是,您不必包装整个 third-party API,也不必将包装器表达为 third-party 函数/宏的直接类似物。

但是还有这个:

  • 选项 3:使您自己的结构对图书馆的客户不透明。这将需要您为 all 您支持的访问类型提供合适的函数,因此在这方面您需要做更多的工作,但它允许您声明结构成员(供内部使用仅)您认为最自然的方式。另外,所有访问都通过函数而不是仅通过其中一些可能感觉更一致。这使您可以轻松更改结构的细节,而不会破坏您的库的客户端。

    client-facing header 可能如下所示:

    struct api_response; // members not declared
    
    int api_get_field1(const struct api_response *resp);
    const char *api_get_field2(const struct api_response *resp);
    const char *api_get_user_email(const struct api_response *resp, const char *user);
    // ...
    

    这将由 internal-only、non-distributed header 提供(至少)struct api_response 的完整定义来补充。