C++编写第三方库桩代码报cannot declare pointer to ‘void’ member错误
问题场景
项目引入第三方库及配套头文件,开发完成进入单元测试阶段,需要编写桩(stub)库替代原第三方库。
第三方库头文件中定义的结构体如下:
typedef struct{ int (*init)(int * var); void (*close)(void); } AInterface;
编写桩代码时先后尝试两种实现均编译失败,具体错误如下:
第一种错误实现
int AInterface::*init(int* var) { return 0; } void AInterface::*close(void) {}
编译报错:
stub.cpp:76:33: error: cannot declare pointer to ‘void’ member
void AInterface::*close(void)
第二种错误实现
int initAInterface(int * var); int (AInterface::*init)(int * var) = &initAInterface; int initAInterface(int* var) { return 0; }
编译报错:
error: cannot convert ‘int ()(int)’ to ‘int (AInterface::)(int)’ in initialization
int (AInterface::init)(int var) = &initAInterface;
补充说明:桩代码.cpp文件中未定义main函数。
核心疑问:
- 上述实现的错误点是什么?
- 正确的桩代码实现方式是什么?
错误原因
- 第一种实现的本质是语法认知错误
AInterface是C风格结构体,其中的init、close是普通函数指针类型的成员变量,不是C++类的成员函数,不存在需要在外部实现的AInterface::init、AInterface::close成员函数实体。写法中用到的AInterface::*语法是用来声明指向类成员的指针,和结构体里的函数指针成员完全无关,属于语法误用。 - 第二种实现的本质是类型不匹配
声明的int (AInterface::*init)(int*)是指向AInterface类成员函数的指针,这类指针自带隐式this指针参数,调用约定、内存布局和普通全局函数完全不同,和普通全局函数initAInterface的指针类型int (*)(int*)不兼容,无法直接转换赋值。
两种错误的核心根源是:误将结构体里的C风格函数指针成员,当成了C++类的成员函数来实现。
正确实现方式
C风格结构体里的函数指针本质就是存储函数地址的变量,只需要实现对应签名的普通桩函数,再把桩函数的地址赋值给对应结构体实例的函数指针成员即可,不需要做“成员函数实现”。
根据原第三方库的导出形式,分两种常见实现:
场景1:原库通过接口函数返回AInterface实例
#include "third_party_header.h" // 实现符合签名的桩函数 static int stub_init(int* var) { // 自定义桩逻辑,例如返回测试预期值、打日志等 if (var) *var = 1; return 0; } static void stub_close(void) { // 自定义桩逻辑 return; } // 加extern "C"避免C++符号名改编,保证和原库导出符号一致 extern "C" AInterface* get_a_interface() { static AInterface stub_inst = { .init = stub_init, .close = stub_close }; return &stub_inst; }
场景2:原库直接导出AInterface类型的全局实例
#include "third_party_header.h" static int stub_init(int* var) { return 0; } static void stub_close(void) {} // 全局变量名和原库导出的符号名保持一致即可 extern "C" AInterface g_a_interface = { .init = stub_init, .close = stub_close };
内容的提问来源于stack exchange,提问作者ascarlat
相关产品推荐
相关产品推荐

