Непоследовательное поведение c_char_p между возвратом и назначением указателя - PullRequest
0 голосов
/ 02 января 2019

Рассмотрим следующие функции C:

void AssignPointer(char **p) {
    *p = "Test1";
}

char* Return() {
    return "Test2";
}

Теперь рассмотрим следующий код в Python:

import ctypes

lib = CDLL('LibraryPathHere')

lib.AssignPointer.restype = None
lib.AssignPointer.argtypes = (ctypes.POINTER(ctypes.c_char_p),)

lib.Return.restype = ctypes.c_char_p
lib.Return.argtypes = None

def to_python_string(c_str : ctypes.c_char_p) -> str:
    return c_str.value.decode('ascii')

Теперь работает следующее:

c_str = ctypes.c_char_p()
lib.AssignPointer(ctypes.byref(c_str))
print(to_python_string(c_str))

Однакоследующее дает AttributeError: 'bytes' object has no attribute 'value':

c_str = lib.Return()
print(to_python_string(c_str))

В первом случае отладчик показывает c_str как c_char_p(ADDRESS_HERE).Во втором случае отладчик показывает c_str как b'Test2'.

Так это ошибка в Python / ctypes или я что-то не так делаю?

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Наконец, вот обходной путь для этой проблемы:

Чтобы избежать автоматического преобразования c_char_p в bytes, установите для функции C restype значение c_void_p:

lib.Return.restype = ctypes.c_void_p

Затем cast до c_char_p перед передачей в функцию, которая ожидает c_char_p в качестве общего случая:

void_ptr = lib.Return()
c_str = ctypes.cast(void_ptr, ctypes.c_char_p)
print(to_python_string(c_str))
0 голосов
/ 02 января 2019

ctypes автоматически преобразует c_char_p возвращаемые значения в байтовые объекты.

Основные типы данных, когда возвращаются как результаты вызова сторонней функции или, например, путем извлечения структурычлены поля или элементы массива прозрачно преобразуются в собственные типы Python.Другими словами, если сторонняя функция имеет рестайп c_char_p, вы всегда получите объект байтов Python, не экземпляр c_char_p.

Если вы хотите фактическое значение указателяиспользуйте ctypes.POINTER(ctypes.c_char) в качестве restype.

...