您的位置:首页 > 其它

开发共享库需要遵循的原则

2010-06-08 11:39 197 查看
共享库是给其他程序员使用的,库设计的好不好,不只是自己的问题,还会影响其他程序。
根据经验,我总结了几条设计库时需要遵守的规律

1、 库的通用接口类型
大致分为两种类型
1)库提供的接口,需要在调用之间保持某些信息。
需要提供类似Open/Close的接口,如LIBXX_Handle libxx_Open(struct xx);libxx_Close(LIBXX_Handle)
LIBXX_Handle是一个数据结构的指针,Open内部分配并返回该指针,库的所有内部状态都在该数据结构中。
2)库提供的接口,不需要在调用之间保持信息
上述Open/Close就是不需要的

另外,暴露出来的应该是接口(函数),尽可能不要暴露数据(全局变量)

2、 信息隐藏
凡是属于库内部实现相关的东西,都不应该暴露给用户。因为一方面会使用户使用该接口麻烦,容易出错,另一方面限制了库的扩展性,一旦要修改库的内部实现,那么用户的程序也必须修改。

3、 名字空间问题
1) 最好携带库的名字作为前缀(例如ffmpeg中的libavcodec提供的接口函数,都以avcodec_开头),以减少名字空间冲突。试想,某个应用程序用到了两个第三方的库,这两个库提供了同名函数ParseData,是不是会很头大?
2) 符号名不要怕长,最好能通过名字,大致猜出用途

4、 线程安全问题
除非有足够强大的理由,否则设计库的时候,一定要注意线程安全,因为用户很可能在多线程中调用该库
1) 不得写入全局变量。如果有这种需要,说明接口类型应该为类型1,可以放到LIBXX_Handle中
2) 不得使用局部static变量。如过有这种需要,说明接口类型应该为类型1,可以放到LIBXX_Handle中
3) 其他违反多线程原则的情况,如linux下就不应该使用signal系列函数,另外一些C库函数应该使用线程安全版本

5、 版本与编译环境问题
如果库的接口参数,有struct类型,则必须注意版本与编译环境问题。一般来说,struct类型的第一个成员应该是一个int iSize,每次调用把该成员初始化成struct的长度。
例如struct xx{ int iSize; int iData1;char cData2}; struct xx instance1; instance1.iSize = sizeof(instance1);
为什么需要这个神奇的成员呢?iSize成员的作用如下:
1) 版本一致性检查。如果应用程序编译时使用的动态库版本,和系统中实际安装的库版本不一致,那么对同一结构,应用程序传送给库的iSize的大小很可能和库希望的大小不一致,
这种情况下,库应返回一个错误码
2) 编译环境一致性检查。如果库编译时的struct对齐设置和应用程序编译时的struct对齐设置不一样,那么应用程序传送给库的iSize的大小和库希望的大小不一致,库就可以发现这种情况并返回错误码。
如果没有iSize字段,这种情况下程序必然死掉

6、 内存管理一致性
应用程序分配的内存,由应用程序释放;库分配的内存,由库负责释放。有些情况下,库需要提供一个接口,释放其分配的内存。
应用程序不要直接用free/delete 等释放库分配的内存,因为库可能有自己内部的内存管理机制
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: