1、动态库、静态库介绍
参考博客:《静态库和动态库介绍以及Makefile》;
2、代码目录结构和编译脚本
参考博客:《实际工作开发中C语言工程的目录结构分析》;
3、编写库的流程
(1)明确需求:需求是否合理、需求的使用场景、需求可能遇到的出错情况;
(2)编写设计文档:功能实现的流程图、代码框架;
(3)设计文档的评审:开设计文档的评审会;
(4)编写对外提供的库头文件:拟定库对外的头文件;
(5)头文件的评审;
(6)创建代码的工程目录,编写代码;
(7)能编译出库文件后,编写测试demo程序;
(8)demo程序测试成功,交付库或者和相关模块进行联调;
(9)根据调试情况修改bug;
(10)上传代码,对外提供的头文件要上传到公共目录,采用映射的方式使用头文件;
3、注意事项
3.1、考虑代码规范性
(1)定义变量后注意要初始化,内存申请后先清零;
(2)内存申请后要判断是否成功,指针使用前判断是否为NULL;
(3)一个文件一般只定义一个全局变量,如果需要多个全局变量可以封装成一个结构体;
(4)初始化函数要考虑被重复调用的可能:记录下是否已经初始化成功,初始化成功之后被再次调用则直接返回成功;
(5)对外提供的库头文件要对每个函数和数据类型写清楚注释;库内部使用的函数和结构体只对重要的写注释;
(6)不对本文件之外提供的函数和全局变量用static修饰,定义成局部的;
(7)函数的传参,如果函数内部不需要修改或者不能修改,用const修饰;
(8)函数的大小一般不超过200行,太长的函数考虑拆分;
(9)函数的命名要规范,可以防止函数重名,一般是库的名字开头;比如函数名aaa_xxx:aaa是库的名字,xxx是函数的功能;
(10)尽量不要用数字来表示含义,用枚举来表示则逻辑比较清晰;
(11)函数对传参要做判断,特别是要判断指针是否为NULL;
(12)内存管理:注意谁申请谁释放的原则,不要造成内存泄漏;
3.2、考虑跨平台
(1)需要在不同机器架构间共用的头文件,要考虑32位、64位机器的数据类型所占字节数的差异,不用使用在不同位数机器中有歧义的数据类型;比如指针类型void *:在32位机器中是4字节,在64位机器中是8字节;
(2)如果库中调用linux的标准API,需要考虑这个API在不同的linux版本中是否有差异。可能有些高版本的linux已经不建议使用某些接口,有新的接口来替换旧的接口;
(3)结构体在不同的
3.3、考虑扩展性
(1)数据类型在定义时可保留一些字节;比如在定义结构体时,重要的、将来可能会添加元素的结构体可保留一些字节,将来扩展结构体时去占用这些保留字节,能保证结构体大小不会发生改变;
(2)函数接口保持一定的抽象性;比如将一些操作以函数指针的方式供上层调用,只定义函数指针的格式,将来可以很方便的替换掉函数指针的实体;
(3)定义函数接口时,要保留将来可能会用到但现在用不到的接口,保持架构的完整性。比如定义了库的初始化函数,对应要定义一个库的反初始化函数,虽然这个接口现在用不上,将可能会用到;
(4)库的头文件采用映射的方式,有利于同步;
3.4、考虑库的调试手段
(1)封装打印函数:区分一般打印、调试打印、出错打印,可以通过编译宏或者程序在运行时接收参数的形式,正常运行时关闭一般打印和调试打印,在需要调试时打再打开;
(2)可以将库的打印注册到内核的/proc文件系统中,效果可以参考海思芯片的"/proc/umap"调试手段;
(3)编译库时,Makefile添加"-g"选项,支持gdb调试;
(4)可以考虑错误码,不同的情况返回不同的错误码,便于定位问题;(错误码用枚举不要用纯数字)
3.5、考虑兼容性
(1)对外的头文件,使用基本的、通用的数据类型;比如使用int,不用使用自己封装的Int32等类型;
(2)对外头文件要低的耦合性,不用和其他的库绑定;
(3)C语言写的库,要兼容C++调用;具体参考博客:https://blog.csdn.net/weixin_42031299/article/details/126688788;
3.6、考虑库的交付
(1)在编译库时,把静态库和动态库都编译出来,让使用库的人自行选择;
(2)提供的demo代码,要写一个Readme文档,介绍使用方法;
(3)交互库时,最好以工程文件夹的方式提供,里面编写一个Makefile,让使用者可以一键编译出demo程序。推荐博友有机会熟悉下海思芯片的SDK开发包,里面的文档、脚本写的很详细,几乎就是一键编译;
推荐
给大家推荐一个学校嵌入式知识的网站,博主在大学时候学习嵌入式知识、找工作的时候都在用这个网站,网站里有C语言、Linux等等的笔试题、面试常问问题等等知识,无论是学习基础知识、面试刷题、交流工作经验都是不错的选择。大家一起进步,欢迎留言交流。
链接:学习神器跳转