我有这个示例代码,函数text()
返回一个新分配的字符串:
ffi_test = FFI()
ffi_test.set_source('_test', '''
char* test() { return strdup("hello world"); }
''')
ffi_test.cdef('''
char* test();
void free(void *);
''')
ffi_test.compile(verbose=True)
这很好用:
In [1]: from _test import ffi, lib
In [2]: x = lib.test()
In [3]: ffi.string(x)
Out[3]: b'hello world'
In [4]: lib.free(x)
但是,我无法在文档中找到任何内容,我是否真的需要手动free()
返回的字符串,如果CFFI在返回Python代码后立即获得指针的所有权。
另外,如果我确实需要手动free()
,我是否需要在 cdefs 中公开free()
,或者CFFI是否为它提供了一些更好的方法?< / p>
答案 0 :(得分:5)
从Working with pointers, structures and arrays上的文档和引用正确的部分:
在C中返回指针或数组或结构类型的任何操作都会为您提供一个新的cdata对象。 与“原始”对象不同,这些新鲜的cdata对象没有所有权
因此你必须释放它,它无法承担所有权: 在C中,有许多函数返回指向内存中常量字符串的指针,例如,它不仅没有动态分配,也没有分配或者可以修改。释放那些将是非常错误的。
同样适用于free
,文档说明如下:
另一种方法是声明并调用C malloc()和free()函数,或者像mmap()和munmap()这样的变体。然后,您可以准确控制何时分配和释放内存。例如,将这两行添加到现有的ffibuilder.cdef():
void *malloc(size_t size); void free(void *ptr);
由于正确 C标准库free
用于strdup
返回的指针非常重要,因此您无法依靠CFFI神奇地做正确的事情,相反,如您所怀疑,您应该公开free()
。如果需要,您还可以使用Barmar建议的gc
注册自动清理:
x = ffi.gc(x, lib.free)