对ctypes不太了解,最近刚开始使用它。
我在C-like dll中有一个简单的函数,它返回一个指向动态生成的字符串的指针 它工作正常,但是,因为我手动为字符串分配内存,我应该在使用后释放它。
我有这样的事情:
extern "C" char* DLL_EXPORT func(const char* str1, const char* str2)
{
return getSomeString(str1, str2);
}
// Goal is to call this function correctly from Python.
extern "C" void DLL_EXPORT freeMem(void *mem)
{
if(mem!=NULL)
delete mem;
}
但我不知道,我怎样才能将收到的指针传回Python中删除?
答案 0 :(得分:9)
你走在正确的轨道上。
// TestDLL.cpp
#include <string.h> // strcpy
extern "C" __declspec(dllexport) char* stringdup(const char* str) {
char* p = new char[strlen(str)+1];
strcpy(p,str);
return p;
}
// if you have no good reason to use void*, use the type
// you've allocated. while it usually works for built-in
// types, it wouldn't work for classes (it wouldn't call
// the destructor)
extern "C" __declspec(dllexport) void stringfree(char* ptr) {
// you don't need to check for 0 before you delete it,
// but if you allocate with new[], free with delete[] !
delete [] ptr;
}
在python中:
# Test.py
import ctypes
lib = ctypes.cdll.TestDLL
# this creates a c-style char pointer, initialized with a string whose
# memory is managed by PYTHON! do not attempt to free it through the DLL!
cstr = ctypes.c_char_p("hello ctypes")
# call the dll function that returns a char pointer
# whose memory is managed by the DLL.
p = lib.stringdup(cstr)
# p is just an integer containing the memory address of the
# char array. therefore, this just prints the address:
print p
# this prints the actual string
print ctypes.c_char_p(p).value
# free the memory through the DLL
lib.stringfree(p)
答案 1 :(得分:8)
通常,您在ctypes
中使用的每个函数都应该声明其参数和返回类型,以便Python可以检查正确的参数数量和类型,并将Python对象参数转换为正确的C数据对象。不幸的是,在这种情况下,func
的正常返回值为c_char_p
,但ctypes
会尝试提供帮助并将c_char_p
返回值转换为Python字符串,从而失去访问权限到原始C指针值。相反,您可以将返回类型声明为c_void_p
并使用cast
来检索字符串值,从而使返回值保留为c_char_p
对象。
这是一个例子(Python 3):
import ctypes
func = ctypes.cdll.TestDLL.func
func.argtypes = [ctypes.c_char_p,ctypes.c_char_p]
func.restype = ctypes.c_void_p
freeMem = ctypes.cdll.TestDLL.freeMem
freeMem.argtypes = [ctypes.c_void_p]
freeMem.restype = None
s = func(b'abcdef',b'ghijkl')
s = ctypes.cast(s,ctypes.c_char_p)
print(s.value)
freeMem(s)
答案 2 :(得分:0)
对我来说
#cdll.execute.restype = ctypes.c_char_p # failed to free
cdll.execute.restype = ctypes.POINTER(ctypes.c_char) # worked
p = cdll.execute('...')
print(
ctypes.cast(p, ctypes.c_char_p).value.decode('utf-8')
)
cdll.free_pointer(p)