如何在C程序编译阶段获取C++类的大小?
问题:在C编译阶段获取C++类的大小以实现静态分配
我开发了一个C++库,正在制作C封装供C程序员使用,目前通过裸指针实现了基础功能,具体代码如下:
相关代码
some_class.hpp
namespace AAA { class SomeClass{ int some_func(int a, int b); }; }
c_wrapper.h
#include <stddef.h> typedef void* c_wrapper_some_class_t; extern size_t const SOME_CLASS_SIZE; c_wrapper_some_class_t* some_class_construct(void *mem, size_t size); int some_class_some_func(c_wrapper_some_class_t *obj, int a, int b);
c_wrapper.cpp
#include <new> #include <stddef.h> #include "c_wrapper.h" extern "C" { size_t const SOME_CLASS_SIZE = sizeof(AAA::SomeClass); c_wrapper_some_class_t *some_class_construct(void *mem, size_t size) { if (size < SOME_CLASS_SIZE || mem == nullptr ) { return nullptr; } return new (mem) AAA::SomeClass; // Placement new } int some_class_some_func(c_wrapper_some_class_t *obj, int a, int b){ return reinterpret_cast<AAA::SomeClass*>(obj)->some_func(a,b); } }
main.c
#include <stdlib.h> #include <assert.h> #include "c_wrapper.h" void * mem = malloc(SOME_CLASS_SIZE); c_wrapper_some_class_t* obj = some_class_construct(mem); assert(obj != NULL); int c = some_class_some_func(obj, 1,2);
目前该方案可通过动态分配正常工作,但无法在C编译时获取SomeClass的大小以实现整洁的静态分配(仅能让用户猜测足够大的空间)。我曾考虑编译c_wrapper.o后用objdump提取大小,再通过CMake模板生成自定义头文件,但库面向嵌入式平台且需要具备可移植性,因此想寻求在C程序编译阶段获取C++类大小的方法。
可行解决方案
1. 编译期生成头文件(推荐,可移植)
写一个轻量的C++辅助程序,用来生成包含类大小常量的C头文件,在构建阶段先执行该程序,再编译C代码:
步骤1:编写生成工具gen_size_header.cpp
#include <fstream> #include "some_class.hpp" int main() { std::ofstream out("some_class_c_size.h"); out << "#ifndef SOME_CLASS_C_SIZE_H\n"; out << "#define SOME_CLASS_C_SIZE_H\n"; out << "#include <stddef.h>\n"; out << "static const size_t SOME_CLASS_SIZE = " << sizeof(AAA::SomeClass) << ";\n"; out << "#endif\n"; return 0; }
步骤2:在构建系统中集成(以CMake为例)
# 先编译生成工具 add_executable(gen_size_header gen_size_header.cpp) # 运行工具生成头文件 add_custom_command( OUTPUT some_class_c_size.h COMMAND gen_size_header DEPENDS gen_size_header some_class.hpp ) # 确保C代码依赖生成的头文件 add_library(c_wrapper SHARED c_wrapper.cpp some_class_c_size.h) target_include_directories(c_wrapper PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
步骤3:C代码使用
修改c_wrapper.h,让它包含生成的头文件:
#include <stddef.h> #include "some_class_c_size.h" typedef void* c_wrapper_some_class_t; c_wrapper_some_class_t* some_class_construct(void *mem, size_t size); int some_class_some_func(c_wrapper_some_class_t *obj, int a, int b);
之后C代码就能直接在编译时用SOME_CLASS_SIZE做静态分配:
// 静态分配 char some_class_storage[SOME_CLASS_SIZE]; c_wrapper_some_class_t* obj = some_class_construct(some_class_storage, SOME_CLASS_SIZE);
2. 利用C++条件编译导出常量(半编译期,纯C需链接)
如果不想生成额外头文件,可以通过条件编译让C++编译器计算大小,同时给C编译器提供外部常量:
修改头文件c_wrapper.h
#include <stddef.h> #ifdef __cplusplus #include "some_class.hpp" constexpr size_t SOME_CLASS_SIZE = sizeof(AAA::SomeClass); #else extern const size_t SOME_CLASS_SIZE; #endif typedef void* c_wrapper_some_class_t; c_wrapper_some_class_t* some_class_construct(void *mem, size_t size); int some_class_some_func(c_wrapper_some_class_t *obj, int a, int b);
在c_wrapper.cpp中定义常量
#include <new> #include "c_wrapper.h" extern "C" { const size_t SOME_CLASS_SIZE = sizeof(AAA::SomeClass); // 其余函数保持不变 }
这种方式下,C++代码能在编译期拿到常量值,但纯C代码只能在链接时解析,无法用该常量做静态数组的大小(因为C要求静态数组大小是编译期常量),因此更适合动态分配场景,静态分配还是推荐第一种方法。
3. 封装静态分配接口(简化用户操作)
结合第一种方法,在C封装中直接提供静态分配的辅助宏和函数,降低用户使用成本:
在c_wrapper.h中添加
#include "some_class_c_size.h" // 定义静态存储的宏 #define SOME_CLASS_STATIC_STORAGE(var_name) char var_name[SOME_CLASS_SIZE] // 初始化静态存储的封装函数 c_wrapper_some_class_t* some_class_construct_static(char *static_mem); // 其余原有声明...
在c_wrapper.cpp中实现
extern "C" { // ...原有函数... c_wrapper_some_class_t* some_class_construct_static(char *static_mem) { // 内部已经确保大小足够,无需用户传入 return some_class_construct(static_mem, SOME_CLASS_SIZE); } }
用户使用示例
SOME_CLASS_STATIC_STORAGE(my_class_mem); c_wrapper_some_class_t* obj = some_class_construct_static(my_class_mem);
内容的提问来源于stack exchange,提问作者user2302957
相关产品推荐
相关产品推荐

