Ответ 1
from ctypes import *
charptr = POINTER(c_char)
test = CDLL('test.so')
test.initializetest.argtypes = []
test.initializetest.restype = charptr
test.searchtest.argtypes = [charptr]
test.searchtest.restype = c_int
buf = test.initializetest()
test.searchtest(buf)
print cast(buf, c_char_p).value
# TODO Release the "buf" memory or it will leak.
ИЗМЕНИТЬ
Изначально я использовал c_char_p
для передачи буфера между функциями, но c_char_p
был как указатель const. Если используется как restype
, вы действительно получите Python str
назад. Поэтому для initializetest
он создаст строку из выделенной памяти (путем копирования данных) и выбросит указатель.
Теперь мы создаем новый тип, от POINTER
до c_char
. Затем это используется в обеих функциях.
Для Python этот тип указывает на один char, поэтому мы должны отдать его, чтобы получить целую строку после завершения searchtest
. Мы используем c_char_p
, потому что просто хотим прочитать значение, чтобы указатель const был в порядке.
В качестве побочной заметки это иллюстрирует катастрофический эффект использования c_char_p
с функциями, которые изменяют массив (как это делает выше searchtest
):
>>> libc.memset.argtypes = [c_char_p, c_int, c_int]
>>> foo = 'Python'
>>> foo
'Python'
>>> libc.memset(foo, ord('x'), 3)
44808532
>>> foo
'xxxhon'
>>>
Обратите внимание, как нам удалось изменить неизменяемую строку Python!
Строка настройки argtypes
даже не требуется, поскольку ctypes
принимает c_char_p
, если в качестве аргумента используется Python str
.