应用场景:
当我们在开发一个涉及到第三方sdk库的软件时,比如做一个上位机控制客户端,该客户端当中调用了一份sdk库当中的接口。而这份sdk库,作为上层客户端软件与下层设备进行通信的媒介,可能需要在有真实设备的环境下,才可以进行消息的收发。
这样如果就没有环境的时候运行我们的客户端,可能在调用到sdk接口函数的地方,就出错导致程序无法正常运行。
而我们可能只是希望运行某个跟设备没有交互的功能,不需要真实环境。
那这时我们就可以使用函数打桩,将这些sdk接口函数,使用我们自己临时定义的函数进行代替,让程序走到接口函数的时候,不执行原本的内容,使得程序也能走下去。
相关资源:
函数打桩需要使用到cpp-stub模块,相关文件链接:https://download.csdn.net/download/bangtanhui/89123831
创建工程后,引入cpp-stub/src文件夹下的stub.h头文件。
举例如下:
比如在程序执行到某一步调用sdk接口时,有这么一个接口:
typedef void* BOARDHANDLE;
typedef struct stBoxVersion{
char sVersion[LEN_256] = { 0 };
int nNetSpeed = 0;
}stBoxVersion;
ZVITBOARDDLL int ZVITBOARD_CC
ZVITGetBoxVersion(IN BOARDHANDLE hBoard, stBoxVersion* stBoxInfo);
该接口是用来获取设备版本信息的,函数名为ZVITGetBoxVersion,参数类型分别为BOARDHANDLE和stBoxVersion*,传的是设备句柄和设备信息结构体指针,返回值类型为int,用来判断是否成功。
而我们在没有真实设备环境下,调用这个接口是会出错的,这时就可以提前对该接口进行打桩。打桩简单来说,就是自己定义一个参数类型以及返回值类型,和原接口函数相同的函数,用来代替,内部我们自行实现。使得函数运行到原接口函数的位置时,实际走的是我们定义的接口。
参考代码:
#include "stub.h"
//原接口函数声明,定义不作展示
ZVITBOARDDLL int ZVITBOARD_CC ZVITGetBoxVersion(IN BOARDHANDLE hBoard, stBoxVersion* stBoxInfo);
//实现我们自定义的打桩函数
int sae_stub_get_version(BOARDHANDLE hBoard, stBoxVersion* stBoxInfo)
{
Q_UNUSED(hBoard);
memcpy(stBoxInfo->sVersion, std::string("arm_20240412_R").c_str(), std::string("arm_20240412_R").size());
stBoxInfo->nNetSpeed = 100;
return ZVIT_RTN_OK;
}
int main(){
//初始化stub指针
Stub * stub = new Stub;
//对接口函数进行打桩
stub->set(ZVITGetBoxVersion, sae_stub_get_version);
stBoxVersion stBoxVer;
//由于我们进行了打桩,这里实际调用的是sae_stub_get_version函数
if(ZVIT_RTN_OK != ZVITGetBoxVersion(handle, &stBoxVer)){
LOG(ERROR) << "从SDK接口获取设备版本信息错误";
return -1;
}
return 0;
}