C++对接不可修改C代码时如何获取实例化匿名结构体类型
结论
完全可以在不修改原有C结构体定义的前提下声明目标函数原型,不需要手动复刻匿名结构体内存布局编写重复的命名结构体。从C++11标准开始,直接通过decltype即可提取匿名结构体的原生类型定义别名,类型100%兼容原C代码,无额外开销。
具体实现方法
匿名结构体虽然没有显式声明的类型名,但编译器处理完整的event结构体定义时,已经为每个匿名结构体生成了唯一的原生类型。你只需要通过成员访问表达式提取对应成员的类型即可,不需要提前实例化event对象:
// 引入无法修改的原有C头文件 #include "c_event_define.h" // 直接提取匿名结构体类型并定义别名 using ConnectEvent = decltype(event::connect); using DisconnectEvent = decltype(event::disconnect);
定义别名后就可以直接声明目标函数,参数类型和原生匿名结构体完全匹配:
void onConnect(ConnectEvent* evt); void onDisconnect(DisconnectEvent* evt);
使用说明
- 上述方法拿到的是C头文件中定义的原生匿名结构体类型,不是手动重新定义的新类型,内存布局、字段偏移完全和原C代码一致,不会出现对齐错误、内存踩踏等兼容性问题。
- 传参时直接取对应union成员的地址即可,不需要任何强制类型转换:
void event_dispatch(event* evt) { switch(evt->type) { case EVT_CONNECT: onConnect(&evt->connect); // 类型完全匹配 break; case EVT_DISCONNECT: onDisconnect(&evt->disconnect); break; } } - 该写法不需要依赖
declval或者已实例化的event变量,decltype可以直接解析event::connect这类限定名成员表达式的类型,全部逻辑在编译期完成,没有任何运行时开销。
不推荐方案
手动编写和匿名结构体内存布局一致的命名结构体属于下策:一旦后续C代码修改了匿名结构体的字段、调整成员顺序或对齐规则,手动编写的结构体不会同步更新,极易引发隐蔽的内存问题,维护成本极高。只有项目仍在使用C++03及更早、不支持decltype的版本时,才需要考虑这种方案,或者直接用void*传参后在函数内部做类型转换。
内容的提问来源于stack exchange,提问作者Adam VZ
相关产品推荐
相关产品推荐

