当前位置: 首页 > article >正文

Linux上位机开发实战(编写API库)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        我们自己编写linux上位机软件的时候,尽量都是通过框架+库的形式来开发。这就是所谓的低耦合,高内聚。相似的功能、模块和算法,都可以做成一个静态库,或者是动态库。实际操作中,客户一般喜欢设计为动态库。因为相比较动态库而言,静态库需要重新编译,比较麻烦。而动态库,即使有bug,直接替换dll、so文件即可。

1、API库的构成

        提供给客户的API库,从技术上说一般包含了head头文件、so动态库文件即可。另外,从版权保护的角度来说,通常还包含一个license文件,或者是一个usb key。

2、编程语言

        通常来讲,接口都会是c语言开发的,实现部分可以是c,也可以是c++。这样,即使客户是用其他语言开发的,也只需要把库文件简单做一个语言封装,这样就可以比较容易地转到其他编程语言,比如说c#、java、python、js、ruby、perl、go等等。

3、基本原则

        对外输出的动态库,最重要的原则,就是只提供必要的信息,隐藏实现的细节。对外提供的函数,一般都是包括在header头文件里面。中间如果涉及到复杂的结构体,最好也是用void*表示。实际开发库的时候,我们自己习惯用cpp开发,但是发布给客户,一定要用extern "C"包装一下。

4、文档部分

        除了技术的部分,详细的使用文档也是必不可少的。每一个api是什么意思,对应的参数是什么,都需要详细地告诉用户。用户可能也不一定看,但是交付的时候,还是有必要提供的。和代码版本一样,文档部分,我们也要做好版本管理。

5、demo代码

        前面说过,客户拿到API库之后,未必会认真查看文档。这种情况下,把范例做好,就可以极大地降低我们开发的工作量。另外,客户的行业、开发水平、人员构成也是千差万别,所以example需要尽量简单,api的命名也尽量简单一些。功能最好直接一点,比如生成的二维码、条形码、人脸识别的位置和概率、车牌识别位置和内容,这种是最合适的。

6、举例说明

        假设我们需要写一个图像处理的库。这个时候就需要把实现和接口分开。这里说的分开,并不是说头文件和cpp文件分开,而是说api接口,和类实现分开。

        假设实现是这样的,

// header file
#ifndef IMG_PROGRAME_FRAME_H
#define IMG_PROGRAME_FRAME_H

class ImgProgrameFrame
{
public:
	ImgProgrameFrame();
	~ImgProgrameFrame();

	bool Initialize(bool isRGB, int width, int height);
	int GetWidth();
	int GetHeight();
	bool GetResult(void* p_img, void* p_result);

private:
	void InnerProcess(); // other function defined here

};
#endif

// cpp file
ImgProgrameFrame::ImgProgrameFrame() {}
ImgProgrameFrame::~ImgProgrameFrame() {}
bool ImgProgrameFrame::Initialize(bool, int, int) { return false; }
int ImgProgrameFrame::GetWidth() { return 0; }
int ImgProgrameFrame::GetHeight() { return 0; }
bool ImgProgrameFrame::GetResult(void*, void*) { return true; }
void ImgProgrameFrame::InnerProcess() {}; // other function implementation

        但是给客户的API接口肯定不是这样,上面的实现只能我们自己看到。不可能把class的细节都给客户,

// header file
#ifndef IMG_PROGRAME_FRAME_API_H
#define IMG_PROGRAME_FRAME_API_H

void Initialize(bool isRGB, int width, int height);
int GetWidth();
int GetHeight();
bool GetResult(void* img,void* param);
#endif

// cpp file
static class ImgProgrameFrame _gFrame;
void Initialize(bool isRGB, int width, int height)
{
	_gFrame.Initialize(isRGB, width, height);
}

int GetWidth() { return _gFrame.GetWidth(); }
int GetHight() { return _gFrame.GetHeight(); }
bool GetResult(void* img, void* result) { return _gFrame.GetResult(img, result); }

        和具体的实现相比较,对外提供的接口都比较简洁。类中的变量、私有函数、部分public函数都会做一个提取之后,再转交给客户。或者说,我们提供给客户的部分,只是客户愿意付费的那部分。这是比较方便、也比较合理的一个做法。

        当然如果需要并发处理,一般就会生成一个动态的ImgProgrameFrame对象,通过void*给客户,每次客户使用的时候再传进来即可。类似于这样,

// header file
#ifndef IMG_PROGRAME_FRAME_API_H
#define IMG_PROGRAME_FRAME_API_H

void* InitializeObject(bool isRGB, int width, int height);
int GetWidth(void* p);
int GetHeight(void* p);
bool GetResult(void*p, void* img, void* result);
#endif

// cpp file
void* InitializeObject(bool isRGB, int width, int height)
{
	ImgProgrameFrame* p = new ImgProgrameFrame();
	p->Initialize(isRGB, width, height);
	return (void*)p;
}

int GetWidth(void* p)
{
	return ((ImgProgrameFrame*)(p))->GetWidth();
}

int GetHeight(void* p)
{
	return ((ImgProgrameFrame*)(p))->GetHeight();
}

bool GetResult(void*p, void* img, void* result)
{
	return ((ImgProgrameFrame*)(p))->GetResult(img, result);
}

http://www.kler.cn/a/600398.html

相关文章:

  • VitePress由 Vite 和 Vue 驱动的静态站点生成器
  • Python:单例模式魔法方法
  • 【机器学习】--二分类
  • flink广播算子Broadcast
  • matlab近似计算联合密度分布
  • 当汉堡遇上便当:TypeScript命名空间 vs JavaScript模块化
  • 销售易CRM:技术革新助力客户关系管理智能化
  • DHCPv6 Stateless Vs Stateful Vs Stateless Stateful
  • 关于网络的一点知识(持续更新)
  • 【第二月_day7】Pandas 简介与数据结构_Pandas_ day1
  • 数据结构——链式队列
  • Spring Security核心源码和功能实现
  • M芯片mac安装Linux虚拟机
  • HTML和CSS基础
  • 数据结构初阶-二叉树的应用
  • 1688关键字API接口解析:(实战案例)
  • Day110 若依-基础
  • mysql数据实时全量+增量迁移
  • 【论文笔记】生成对抗网络 GAN
  • 统一开放世界与开放词汇检测:YOLO-UniOW无需增量学习的高效通用开放世界目标检测框架