C/C++的开源库大部分还是比较好的,体现在:
1、开源,意味着可以使用lib或源码,这点很灵活。
2、功能现成,意味着我们不需要再重复劳动。
3、一般较符合标准国际,通用性好。
4、一般免费,license较宽松,具体见GPL LGPL BSD等license,然而我们是天朝的特殊情况,你懂的。。
然而好的库,其实未必好用,有很多坑,甚至不明显,甚至坑很深:
1、即便成熟的库(尤其是C的),一般都是需要初始化。
例如pjsip里的pjlib pjutil pjnath等基本都有个xxx_init(),而上来就用或者忘记使用这些init的代码就会带来问题。
2、函数功能的坑,比如pj_str_t pj_str(char * str)这个函数,不翻源码,你能知道这是个浅拷贝函数吗?
假如你给它传了个临时变量的str,那你就给自己挖了个坑,什么时候掉进去是未知的。
2、异常的崩溃问题,即便你定位到该位置,缺发现原本很正常的代码却崩溃了。
注释掉几行代码,发现崩溃延后了,这说明是其他问题引起的堆栈崩溃,而不是该几行代码的问题。
而这种问题的解决基本是无迹可寻的,只有个“0x0000005”不可访问之类的异常。
这样的问题很可能是该库或者该接口有依赖:
比如,使用pjlib库的外部线程必须被注册给pjlib库,本人使用pjnath库就遇到了这样的问题。
vs2012 编译的pjnath icedemo例子没问题,自己改来用在dll里 结果 出现 堆栈被破坏
# define PJ_CHECK_STACK()// pj_thread_check_stack(__FILE__, __LINE__)
把该宏空置失效,可以解决,但是百思不得其解。
后来终于发现是外部使用线程并未注册给pjlib,还是尼玛翻源码发现的。
pj_thread_register的说明:
This function must be called in the context of the thread being registered.
* When the thread is created by external function or API call,
* it must be 'registered' to PJLIB using pj_thread_register(), so that it can
* cooperate with PJLIB's framework.
这引起了我的怀疑,在外部线程函数优先调用下边的函数来尝试
- bool ice_register_thread()
- {
- if(!pj_thread_is_registered())
- {
- pj_thread_desc desc;
- pj_thread_t* thed;
- if (pj_thread_register(NULL,desc,&thed) == PJ_SUCCESS)
- {
- return true;
- }
- }
- return false;
- }
原来存在的正常位置代码堆栈崩溃问题消失了。
这个现象里是pjnath依赖pjlib和pjutil,而pjlib依赖“调用pjlib库的外部线程必须注册给它”这个条件。
而这个条件在pjnath的文档或wiki里并未体现,所以有时候要调查清楚所有的依赖问题来定位异常。
3、使用源码和lib或dll的经常有区别。
比如pthread for win32的版本使用静态库的时候,必须使用成对的初始化和销毁函数。而用dll就没这问题。
4、跨平台问题。
越成熟的库跨平台性能越好,linux和windows下的编译和使用文档健全,用的人多,出了问题,度娘、谷哥一般能解决问题。
最后,谈下自己的经验:
选库条件:1、出的早2、用的人多3、依赖其他库少4、各个平台开发使用文档详细5、最好用c++的库(c库有些回调函数是满天飞的)6、能满足自己需要,其他功能越少越好。
用库方法:1、涉及的文档务必仔细看2、遇到问题不要轻易放弃,可选用排除法定位问题类型3、务必多尝试4、搞不定的,先变通实现最好
最后,驾驭开源库是一个时间未知的工作,但是我们尽量缩短时间。