Как обрабатывать массив строк (char **) в ctypes в 64-битной среде? - PullRequest
0 голосов
/ 23 февраля 2011

Я использую ctypes для работы с libgphoto2 в Python. Следующий код успешно выполняется на 32-разрядной машине, но завершается с ошибкой сегментации на 64-разрядной машине (Linux, Ubuntu):

import ctypes

gp = ctypes.CDLL('libgphoto2.so')
a = gp.gp_library_version(0)
x = ctypes.c_char_p.from_address(a)
x.value

libphoto2, ctypes и python все из репозиториев, поэтому я предполагаю, что проблема в моем коде; Мне нужно рассмотреть указатели в более общем смысле или что-то в этом роде. gp_library_version() возвращает const char **, массив строковых констант. Другие gp_* функции работают нормально.

Ответы [ 2 ]

2 голосов
/ 23 февраля 2011

Проблема в том, что по умолчанию ctypes предполагает, что все функции возвращают int, что составляет 32 бита.Но в 64-битной системе указатель составляет 64 бита, поэтому вы отбрасываете верхние 32 бита из возвращаемого значения указателя, поэтому при попытке разыменования этого недопустимого указателя вы получаете ошибку сегмента.

Вы можете изменить ожидаемый тип возвращаемого значения функции, присвоив тип ее атрибуту restype следующим образом:

gp = ctypes.CDLL('libgphoto2.so')
gp.gp_library_version.restype = ctypes.POINTER(ctypes.c_char_p)
a = gp.gp_library_version(0)
print a[0].value
0 голосов
/ 23 февраля 2011

Если вы не аннотируете что-либо о функциях в ctypes, предполагается, что они возвращают 32-битные целые числа. В 32-битных процессах эти целые числа и указатели в основном взаимозаменяемы - это не так для 64-битных сборок.

Просто делаю

gp.gp_library_version.restype = ctypes.c_void_p

, прежде чем ваш звонок должен быть достаточным в этом случае (вам все равно понадобится x = ctypes.c_char_p.from_address(a) строка).

Проверьте документацию по API, следует ли освободить этот указатель самостоятельно после его использования (возможно, в этом случае да).

...