Ctypes и string

У меня есть простой C файл:

char* initializetest() {
    char * test = malloc(1000);
    return test;
}

int searchtest( char* test )
{
   strcpy(test,"test");
   return 0;
}

main()
 {
    char *test = initializetest();
    searchtest(test);
    printf("%s\n", test );
}

и файл python:

from ctypes import *

class Test(object):
    def __init__(self):
        self.test_library=CDLL("test.so")
        self.test_initialize = self.test_library.initializetest
        self.test_search = self.test_library.searchtest
        self.test_search.restype=c_int
        self.m = self.test_initialize()

    def search(self):
        self.test_search(self.m)
        print self.m

r = Test()
print r.search()

Как получить строку "test" в python?

Ответ 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.

Ответ 2

Возможно, с помощью restype, например описанный здесь

class Test(object):
    def __init__(self):
        self.test_library=CDLL("./test.so")
        self.test_initialize = self.test_library.initializetest
        self.test_initialize.argtypes = []
        self.test_initialize.restype = c_char_p # c_char_p is a pointer to a string
        self.test_search = self.test_library.searchtest
        self.test_search.restype = c_int
        self.test_search.argtypes = [c_char_p]
        self.m = c_char_p(self.test_initialize())

    def search(self):
        return self.test_search(self.m).value

r = Test()
print r.search()

EDIT: исправлено после теста:)

Ответ 3

установите c_char_p как возвращаемый тип init func. c_char_p означает char * (NUL завершен)