c - 编写 C 动态库 [DSOs] 的良好实践(二进制兼容性 + 内存管理)

标签 c linux memory-management shared-libraries binary-compatibility

我有一些编写 C 库的经验,但我从未阅读过任何描述编写此类库时的良好做法的正式文档。我的问题主要涉及两个主题:

  1. 如何保持二进制兼容性? (我听说过 pImpl 惯用法,d 指针)
  2. 如何设计保持向后兼容的接口(interface)?

从我的研究中我可以看到关于二进制兼容性的主要事情是,我可以通过使用 pImpl 惯用语使库二进制兼容,但即使在使用 pImpl 时更改结构/添加新数据成员等也会影响它的二进制兼容性。另外,有没有办法在不破坏二进制兼容性的情况下向库添加新方法/函数?我假设添加这些东西会改变库的大小和布局,从而破坏兼容性。

是否有检查二进制兼容性的工具?

我已经阅读了这些文章。还有其他我可以细读的文档吗?

http://en.wikipedia.org/wiki/Opaque_pointer

http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++

此外,是否有文章描述了在设计库接口(interface)的上下文中内存的所有权问题。一般约定是什么?谁拥有内存,多长时间,谁负责释放内存等?

最佳答案

关键的兼容性问题是:

  • 函数签名
  • 库和调用者访问的任何数据的格式
  • 调用者访问的库中的全局变量
  • 由于 header 中的宏/内联函数而在调用者中结束的库代码
  • #define/enum 共享 header 中的常量值

所以我能给出的最佳指南列表是:

  • 切勿更改任何公共(public)接口(interface)的签名(返回/参数类型)。如果您需要扩展一个接口(interface),而不是添加一个接受更多参数的新函数(想想 dupdup2waitwaitpid ).
  • 尽可能使用指向完全封装的不透明数据对象的指针,甚至不要在公共(public) header 中公开此类结构的定义(使它们成为不完整的 struct 类型)。
  • 当你确实想要共享一个结构时,安排调用者从不声明该结构类型的变量,而是调用库中的显式分配/释放函数。切勿更改现有成员的类型或删除现有成员;相反,只在结构的末尾添加新成员。
  • 不要暴露库中的全局变量,句号。除非您了解“复制重定位”,否则最好不要问为什么。只是不要这样做。
  • 不要将内联函数或包含代码的宏放入您的库的公共(public) header 中,除非使用将永久保留的已记录的公开接口(interface)。如果他们戳穿不透明数据对象的内部结构,当您决定更改内部结构时,他们会导致问题。
  • 不要重新编号现有的 #define/enum 常量。仅添加具有以前未使用的值的新常量。

如果您遵循这些准则,我认为您至少已覆盖 95%。

关于c - 编写 C 动态库 [DSOs] 的良好实践(二进制兼容性 + 内存管理),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7217258/

相关文章:

linux - 在 bash 提示中插入新行

c - 使用libao播放音频文件

c# - C# 中的静态 XML 序列化程序是否会导致内存过度增长?

c++ - 内存管理模式

c - 使用 Fork() 和 Pipe() 将文件拆分为多个子进程

c - 想要构建只有一个内核和一个二进制文件的裸 Linux 系统

c++ - 在 windows 上编译 MSVC 是绝对必要的吗?

linux - 如何删除以破折号开头的文件(在类 Unix 模式下)

c - 大O小澄清

代码在 macOS 上逻辑上有效,但在 Ubuntu 16.04.5 上无效