Бесплатный calloc в общей библиотеке с использованием ctypes
У меня есть эта структура:
struct result {
int position;
int *taken;
};
struct result get_result(int pos, int take[]){
struct result res;
res.position = pos;
res.taken = take;
return res;
}
Который я вызываю в функции:
struct result get_taken_values(){
//some code
int position = 0;
int* chosen = calloc(9, sizeof(int));
//some more code
struct result res;
res.position = position;
res.taken = chosen;
return res;
}
Если бы я использовал это в основном, я бы просто позвонил free(res.taken) in the end
,
Но я превращаю это в общую библиотеку, используя:
gcc -fPIC -c get_taken_values.c
ld -shared -soname libtest.so.1 -o my_library.so -lc get_taken_values.o
Я буду использовать эту библиотеку в Python, используя ctypes.
Нужно ли освобождать calloc, если да, то как мне это сделать?
1 ответ
Предполагая, что вам нужен массив переменного размера для taken
тогда вы можете создать ctypes.Structure
дай ему __del__
метод, который будет вызывать free
, Ты можешь позвонить free
при загрузке libc
, __del__
вызывается после того, как последняя ссылка на объект выпадает из области видимости. С помощью __del__
может вызвать проблемы, если ваши объекты содержат циклические ссылки, так как python не будет знать, какие объекты вызывать __del__
во-первых (так что это не так, он просто держит объекты в памяти).
from ctypes import Structure, c_int, POINTER, CDLL
from ctypes.util import find_library
__all__ = ["get_taken_values", "Result"]
libc = CDLL(find_library("c"))
libmy_library = CDLL("./my_library.so")
class Result(Structure):
_fields_ = [
("position", c_int),
("taken", POINTER(c_int)),
("size", c_int)
]
def __str__(self):
return "result(position={}, taken={})".format(
self.position, self.taken[:self.size])
def __del__(self):
libc.free(self.taken)
get_taken_values = libmy_library.get_taken_values
get_taken_values.argtypes = ()
get_taken_values.restype = Result
if __name__ == "__main__":
result = get_taken_values()
print("position is {} and value at position is {}".format(
result.position, result.taken[result.position]))
print(result)
Это делает предположение, что экземпляр питона Result
является владельцем памяти. Кроме того, если taken
на самом деле имеет переменный размер, то вам нужно будет включить размер члена в вашей структуре, что Result
Рекомендации. Если taken
это фиксированный размер, тогда вы можете просто объявить взятый как массив в структуре, забыть об использовании free, и использовать c_int * 9
скорее, чем POINTER(c_int)
при объявлении типа taken
в питоне.