使用Ctypes封装DLL遇断言失败(string != NULL)问题求助
解决Ctypes调用DLL时sprintf的NULL指针断言错误
首先,你的问题出在不必要的指针转换上——你不需要用addressof和cast来传递字符串缓冲区,create_string_buffer返回的对象本身就可以直接作为char*指针传入DLL函数。
修复后的完整代码
import ctypes from ctypes import c_double, POINTER # 加载并配置DLL dll = ctypes.WinDLL("MyDLL.dll") f = dll.compute_result f.restype = c_double f.argtypes = [c_double, c_double, POINTER(ctypes.c_char), POINTER(ctypes.c_char)] # 输入变量 var1 = 1.1 var2 = 2.2 # 创建足够大的字符串缓冲区 size = 1024 buf1 = ctypes.create_string_buffer(size) buf2 = ctypes.create_string_buffer(size) # 直接传递缓冲区对象,无需额外转换 result = f(var1, var2, buf1, buf2) # 读取并解码输出消息 print("Output Message 1:", buf1.value.decode('utf-8')) print("Output Message 2:", buf2.value.decode('utf-8')) print("Computed Result:", result)
错误原因解释
你之前用cast(addressof(buf1), POINTER(c_char))的操作完全是画蛇添足:
create_string_buffer返回的是ctypes.c_char_Array_xxx类型的对象,当你把它直接传递给需要POINTER(c_char)的函数时,ctypes会自动将其转换为指向数组首元素的有效指针(也就是C语言里的char*)。- 多余的
addressof和cast操作反而破坏了ctypes的自动类型转换逻辑,导致传入了无效的空指针,触发了sprintf函数的string != NULL断言检查。
额外注意事项
- 确保DLL函数导出正确:如果你的DLL是用C编译的,必须用
extern "C"修饰函数,避免C的名字修饰(name mangling),否则Python会找不到compute_result函数:
extern "C" __declspec(dllexport) double compute_result(double var1, double var2, char *output_message1, char *output_message2){ double result = var1 + var2; snprintf(output_message1, 1024, "useful output message 1"); snprintf(output_message2, 1024, "useful output message 2"); return result; }
- 替换不安全的sprintf:建议把C++代码里的
sprintf换成snprintf,明确指定缓冲区大小,避免潜在的缓冲区溢出风险。 - 编码匹配:因为你用的是
c_char(对应C的char类型),DLL输出的是ASCII/UTF-8编码的字符串,Python读取时需要用decode('utf-8')转换为原生字符串。
内容的提问来源于stack exchange,提问作者SLhark
相关产品推荐
相关产品推荐

