通过回调缓冲区分配(python ctypes)

时间:2015-03-14 03:03:13

标签: python pointers ctypes

我一直在寻找在Python中分配缓冲区的方法,并使用Python ctypes库将其安全地传递给C.

作为第一步,我实现了一个回调来分配缓冲区,函数类型为CFUNCTYPE(c_long, POINTER(c_void_p), c_long)

版本1,使用CRT malloc

def alloc(buf, size):
    print type(buf)
    print "allocating string of size-> ", size
    buf[0] = vcrt_dll.malloc(size)
    return 0

版本2,使用create_string_buffer

def string_allocator(buf, size):
    print type(buf)
    print "allocating string of size-> ", size
    buf[0] = create_string_buffer(size)
    return 0

我使用下面的代码将指针传递给C. TryAlloc是一个为Python调用者填充消息的C函数。

C代码:

long TryAlloc(char **buf)
{
    long size(256); // magic number !!!
    allocator((void **)buf, size);
    ZeroMemory(*buf, size);

    char msg[] = "hello world";
    strncpy_s(*buf, size, msg, strlen(msg));

    return 0;
}

Python代码:

def try_alloc():
    buf = c_char_p()
    sample_dll.TryAlloc(byref(buf))    
    print buf.value

使用malloc时,这样可以正常工作,但我需要为分配的缓冲区手动调用free。当我使用字符串缓冲区替代时,它在Python中引发以下错误:

TypeError: incompatible types, c_char_Array_100 instance instead of c_void_p

我看到其他一些线程正在讨论相同的问题(例如,Calling python from C++, through callback, with variable buffer),但我无法找到适当的解决方案。有人可以提出一个干净的方法来实现这个吗?

1 个答案:

答案 0 :(得分:0)

ctypes正试图阻止您以更严肃的方式破坏您的程序。返回的对象create_string_buffer拥有它指向的缓冲区,并且当python对象的引用计数达到0时,期望释放此缓冲区。如果您要手动释放此内存,则程序稍后会导致分段错误python对象试图释放它指向的缓冲区。实际上,您不应该尝试释放ctypes模块分配的任何内存。例如:

i = c_int(10)
p = pointer(i)
vcrt_dll.free(p) # error

您应该手动释放内存的唯一时间是您正在使用的C库返回的堆内存(例如vcrt_dll.malloc)。