如何用Python ctypes镜像包含std::string的C++结构体?
用ctypes读取含std::string的C++结构体内存值
方案一:模拟std::string的内存布局读取
C++的std::string内存布局会因编译器(如GCC/Clang、MSVC)略有差异,但多数64位平台下的标准实现是由三个8字节字段组成:指向字符串数据的指针、字符串长度、容量。你可以用ctypes定义对应结构来匹配:
import ctypes # 适配GCC/Clang的std::string布局(64位) class StdString(ctypes.Structure): _fields_ = [ ("data_ptr", ctypes.c_void_p), # 指向字符串数据的指针 ("length", ctypes.c_size_t), # 字符串实际长度 ("capacity", ctypes.c_size_t) # 已分配的内存容量 ] # 修改后的结构体定义,替换原char数组为StdString class AppStructFoo(ctypes.Structure): _fields_ = [ ("next", ctypes.c_void_p), ("prev", ctypes.c_void_p), ("name", StdString), ("identifier", ctypes.c_int32), ("flag", ctypes.c_int), ("idname", StdString), ("typeinfo", ctypes.c_void_p), ("type_legacy", ctypes.c_int16), ("ui_order", ctypes.c_int16), ("custom1", ctypes.c_int16), ("custom2", ctypes.c_int16), # 其他字段... ] # 读取结构体并获取目标值 node_struct = AppStructFoo.from_address(memory_address) print(node_struct.custom2) # 若需要读取字符串内容 name_str = ctypes.c_char_p(node_struct.name.data_ptr).value.decode('utf-8') print(name_str)
注意:如果目标程序用MSVC编译,
std::string会有小字符串优化(SSO),布局会更复杂,需要对应调整结构体定义。这种方案的局限性是依赖具体编译器实现,跨平台可能失效。
方案二:跳过std::string字段,直接计算偏移读取目标值
如果只需要读取custom2这类后续字段,完全可以跳过std::string的具体布局,通过计算字段偏移量直接读取目标内存地址:
import ctypes # 定义临时结构体,用占位符模拟std::string的大小(保证对齐正确) class TempStruct(ctypes.Structure): _fields_ = [ ("next", ctypes.c_void_p), ("prev", ctypes.c_void_p), # 用3个void*占位,匹配64位std::string的24字节大小 ("name", ctypes.c_void_p * 3), ("identifier", ctypes.c_int32), ("flag", ctypes.c_int), ("idname", ctypes.c_void_p * 3), ("typeinfo", ctypes.c_void_p), ("type_legacy", ctypes.c_int16), ("ui_order", ctypes.c_int16), ("custom1", ctypes.c_int16), ] # 计算custom2相对于结构体起始地址的偏移量 custom2_offset = ctypes.sizeof(TempStruct) # 直接读取目标值 custom2_value = ctypes.c_int16.from_address(memory_address + custom2_offset).value print(custom2_value)
这种方案的优势是不依赖std::string的具体实现,无需关心字符串内容,只专注于目标字段的偏移,稳定性更高。
内容的提问来源于stack exchange,提问作者DB3D
相关产品推荐
相关产品推荐

