Python通过ctypes调用D语言so库gph结构体函数报错求助
问题排查与解决步骤
1. 先纠正函数调用的核心错误
你误将全局函数print_gph当作结构体成员函数调用,传入的c_void_p()是成员函数的this指针,这完全不符合全局函数的调用约定——全局函数不需要额外的this参数,直接传入结构体实例即可,这是触发「Bad address」的首要原因。
2. 确认D string与Python ctypes的内存布局匹配
D的string是切片类型,本质是固定布局的结构体:
struct String { char* ptr; // 指向字符数组的指针 size_t length; // 字符串长度(字节数) }
Python侧必须严格对应这个布局定义结构体,否则会因内存错位导致错误:
import ctypes # 映射D的string切片 class DString(ctypes.Structure): _fields_ = [ ("ptr", ctypes.c_char_p), ("length", ctypes.c_size_t) ] # 映射D的gph结构体(替换s1/s2为你实际的成员名) class Gph(ctypes.Structure): _fields_ = [ ("s1", DString), ("s2", DString) ]
如果你的Python结构体用x_p/x_len但字段顺序、类型不匹配,会直接破坏内存结构,引发地址错误。
3. 正确构造Python侧的结构体实例
要将Python字符串转换为兼容D的切片,需编码为字节串并绑定指针,同时避免悬空指针:
def py_to_dstr(py_str): # 编码为UTF-8字节串,保留引用防止被GC回收 byte_str = py_str.encode("utf-8") d_str = DString() d_str.ptr = ctypes.c_char_p(byte_str) d_str.length = len(byte_str) return d_str # 构造Gph实例 gph_inst = Gph() gph_inst.s1 = py_to_dstr("第一个测试字符串") gph_inst.s2 = py_to_dstr("第二个测试字符串")
4. 正确加载并调用.so库的全局函数
必须显式声明函数的参数类型和返回值类型,避免ctypes自动转换导致的调用栈错误:
# 编译后的.so路径 lib = ctypes.CDLL("./your_gph_lib.so") # 声明函数参数(如果D函数接受指针则用ctypes.POINTER(Gph)) lib.print_gph.argtypes = [Gph] # 声明返回值(无返回值则设为None) lib.print_gph.restype = None # 调用函数(如果D函数是ref引用传递,改用ctypes.byref(gph_inst)) lib.print_gph(gph_inst)
5. 验证D侧的函数与编译命令
确保D的print_gph是全局函数,参数类型正确:
struct gph { string s1; string s2; } // 全局函数,接受值传递或ref引用传递均可 void print_gph(gph g) { import std.stdio; writeln("s1: ", g.s1); writeln("s2: ", g.s2); }
编译.so的正确命令(dmd为例):
dmd -shared -fPIC your_d_source.d -o your_gph_lib.so
常见错误总结
- 多余的
c_void_p()参数:全局函数不需要this指针,直接删除 - 结构体布局不匹配:D string是
ptr在前、length在后,Python必须严格对应 - 未声明函数参数类型:ctypes默认参数转换会破坏调用栈,必须显式声明
argtypes和restype - 字符串悬空指针:Python字节串需保留引用,避免被GC回收导致指针失效
内容的提问来源于stack exchange,提问作者backtrack
相关产品推荐
相关产品推荐

