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() 

Как получить «тестовую» строку в python?

 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 он создаст строку из выделенной памяти (путем копирования данных) и выбросит указатель.

Теперь мы создаем новый тип – c_char для c_char . Затем это используется в обеих функциях.

Для Python этот тип указывает на один символ, поэтому мы должны отдать его, чтобы получить всю строку после 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 установки argtypes даже не требуется, потому что ctypes предполагает c_char_p если в качестве аргумента используется Python str .

Может быть, используя редип, как описано здесь

 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: исправлено после теста 🙂

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