如何在 Python 中使用 ctypes,当 "C" 回调的参数为 char **
How to use ctypes in Python, when the "C" callback has param with char **
我正在尝试使用包含一个 lib.so
文件的 python 代码进行编程。 C 语言有一个回调方法,要我将我的字符串放入给定地址。
我花了整整一周的时间来解决这个问题....
现在,我已将字符串传递给 C。
但是下一个问题出现了...... "C" 不能 free()
我的字符串指针由 python.
创建
Error in `/usr/bin/python': free(): invalid pointer
另外一个头码我省略了
typedef struct
{
int (*Info) (int resId,char **outbuff);
} OptFuncs;
这是 C 代码
OptFuncs g_sdk_opt_funcs = {NULL};
int SDK_INIT(OptFuncs *optfuncs)
{
g_sdk_opt_funcs = *optfuncs;
return 0;
}
int SDK_RUN()
{
resId = 6604;
char *szvalbuf = NULL;
g_sdk_opt_funcs.Info(resId,&szvalbuf);
if(szvalbuf) {free(szvalbuf); szvalbuf = NULL;}
// I guess that's the problem.
return 0;
}
这里是使用C语言的例子:
int myInfo(int resId,char **outbuff)
{
int iret = 0;
*outbuff = NULL;
char buff[512];
int buflen = sizeof(buff);
memset(buff,0,sizeof(buff));
if(resId == 6604)
{
snprintf(buff,buflen,"4GB");
}
if(iret == 0)
{
*outbuff = (char*)malloc(strlen(buff)+1);
strcpy(*outbuff,buff);
}
return iret;
}
int main(int argc, char *argv[])
{
OptFuncs optfuncs={NULL};
optfuncs.Info = myInfo;
int ret = SDK_INIT(&optfuncs);
ret = SDK_RUN();
}
它适用于纯 C。
我的 python 函数是:
lib = CDLL('./lib/lib.so')
infoCallback = CFUNCTYPE(c_int, c_int, POINTER(POINTER(c_char)))
class OptFuncs(Structure):
_fields_ = [("Info", infoCallback)]
def my_info(res_id, out_buff):
iret = 0
out_buff[0] = None
if res_id == 6604:
buff = '16GB'
char_array = create_string_buffer(buff)
out_buff[0] = cast(char_array, POINTER(c_char))
return iret
optFuncs = OptFuncs()
optFuncs.Info = infoCallback(my_info)
# initialize the lib‘s callback.
lib.SDK_INIT.argtypes = [POINTER(OptFuncs)]
ret = lib.SDK_INIT(pointer(optFuncs))
# run the lib‘s main func.
ret = lib.SDK_RUN()
然后错误发生了。
Error in `/usr/bin/python': free(): invalid pointer
我做错了吗?
问题是内存由 Python 的 C 运行时库中的 create_string_buffer
分配,并在 DLL 的运行时库中释放。它们可能不是用相同版本的编译器编译的,而且我们内部不知道 create_string_buffer
是如何分配缓冲区的。 DLL 接收到的指针可能不是分配的指针。 create_string_buffer
可能会分配比您预期更多的内容来存储 ctypes 元数据。您不想释放由 Python.
管理的内存
要解决此问题,请确保在 DLL 中分配和释放数据。例如,将此函数添加到 DLL 并调用它而不是 create_string_buffer
:
C
API char* SDK_MALLOC(const char* buff)
{
char* s = malloc(strlen(buff) + 1);
strcpy(s,buff);
return s;
}
Python
lib.SDK_MALLOC.argtypes = ()
lib.SDK_MALLOC.restype = POINTER(c_char)
my_info
变为:
def my_info(res_id, out_buff):
iret = 0
out_buff[0] = None
if res_id == 6604:
buff = b'16GB'
char_array = lib.SDK_MALLOC(buff)
out_buff.contents = char_array
return iret
我正在尝试使用包含一个 lib.so
文件的 python 代码进行编程。 C 语言有一个回调方法,要我将我的字符串放入给定地址。
我花了整整一周的时间来解决这个问题....
现在,我已将字符串传递给 C。
但是下一个问题出现了...... "C" 不能 free()
我的字符串指针由 python.
Error in `/usr/bin/python': free(): invalid pointer
另外一个头码我省略了
typedef struct
{
int (*Info) (int resId,char **outbuff);
} OptFuncs;
这是 C 代码
OptFuncs g_sdk_opt_funcs = {NULL};
int SDK_INIT(OptFuncs *optfuncs)
{
g_sdk_opt_funcs = *optfuncs;
return 0;
}
int SDK_RUN()
{
resId = 6604;
char *szvalbuf = NULL;
g_sdk_opt_funcs.Info(resId,&szvalbuf);
if(szvalbuf) {free(szvalbuf); szvalbuf = NULL;}
// I guess that's the problem.
return 0;
}
这里是使用C语言的例子:
int myInfo(int resId,char **outbuff)
{
int iret = 0;
*outbuff = NULL;
char buff[512];
int buflen = sizeof(buff);
memset(buff,0,sizeof(buff));
if(resId == 6604)
{
snprintf(buff,buflen,"4GB");
}
if(iret == 0)
{
*outbuff = (char*)malloc(strlen(buff)+1);
strcpy(*outbuff,buff);
}
return iret;
}
int main(int argc, char *argv[])
{
OptFuncs optfuncs={NULL};
optfuncs.Info = myInfo;
int ret = SDK_INIT(&optfuncs);
ret = SDK_RUN();
}
它适用于纯 C。
我的 python 函数是:
lib = CDLL('./lib/lib.so')
infoCallback = CFUNCTYPE(c_int, c_int, POINTER(POINTER(c_char)))
class OptFuncs(Structure):
_fields_ = [("Info", infoCallback)]
def my_info(res_id, out_buff):
iret = 0
out_buff[0] = None
if res_id == 6604:
buff = '16GB'
char_array = create_string_buffer(buff)
out_buff[0] = cast(char_array, POINTER(c_char))
return iret
optFuncs = OptFuncs()
optFuncs.Info = infoCallback(my_info)
# initialize the lib‘s callback.
lib.SDK_INIT.argtypes = [POINTER(OptFuncs)]
ret = lib.SDK_INIT(pointer(optFuncs))
# run the lib‘s main func.
ret = lib.SDK_RUN()
然后错误发生了。
Error in `/usr/bin/python': free(): invalid pointer
我做错了吗?
问题是内存由 Python 的 C 运行时库中的 create_string_buffer
分配,并在 DLL 的运行时库中释放。它们可能不是用相同版本的编译器编译的,而且我们内部不知道 create_string_buffer
是如何分配缓冲区的。 DLL 接收到的指针可能不是分配的指针。 create_string_buffer
可能会分配比您预期更多的内容来存储 ctypes 元数据。您不想释放由 Python.
要解决此问题,请确保在 DLL 中分配和释放数据。例如,将此函数添加到 DLL 并调用它而不是 create_string_buffer
:
C
API char* SDK_MALLOC(const char* buff)
{
char* s = malloc(strlen(buff) + 1);
strcpy(s,buff);
return s;
}
Python
lib.SDK_MALLOC.argtypes = ()
lib.SDK_MALLOC.restype = POINTER(c_char)
my_info
变为:
def my_info(res_id, out_buff):
iret = 0
out_buff[0] = None
if res_id == 6604:
buff = b'16GB'
char_array = lib.SDK_MALLOC(buff)
out_buff.contents = char_array
return iret