Python Ctypes передавая указатель на данные - PullRequest
0 голосов
/ 26 апреля 2018

Я обращаюсь к API и не могу получить возвращенные данные. Два указателя с плавающей точкой будут указывать на массив данных. Я должен предположить, что API работает правильно. Другой вызов функции обеспечивает длину данных, которые я получаю. Это значение length ниже при попытке.

C Заголовок для функции

    int function(int, float * data1, float * data2)

ctypes setup

    dll.function.argtypes = (c_int, POINTER(c_float), POINTER(c_float))
    dll.function.restypes = c_int

Неудачная попытка 1:

    x = c_float()
    y = c_float()
    status = dll.function(1, byref(x), byref(y))

Сбой программы ИЛИ запись нарушения прав доступа.

Неудачная попытка 2:

    x = POINTER(c_float)()
    y = POINTER(c_float)()
    status = dll.function(1, x, y)

Ошибка нулевого указателя

Неудачная попытка 3:

    dll.function.argtypes = (c_int, c_void_p, c_void_p)
    x = c_void_p()
    y = c_void_p()
    status = dll.function(1, x, y)

Ошибка нулевого указателя

Неудачная попытка 4:

    array = c_float * length
    x = array()
    y = array()
    status = dll.function(1, byref(x), byref(y))

Сбой программы

Неудачная попытка 5:

    array = c_float * length
    x = POINTER(array)()
    y = POINTER(array)()
    status = dll.function(1, x, y)

Ошибка нулевого указателя ИЛИ ArgumentError: ожидаемый экземпляр LP_c_float вместо LP_c_float_Array_ [length]

Неудачная попытка 6:

    x = (c_float*length)()
    y = (c_float*length)()
    a = cast(x, POINTER(c_float))
    b = cast(y, POINTER(c_float))
    status = dll.function(1, a, b)

Сбой программы

Чего мне не хватает и почему?

Я верю, что аргументы правильны. Я пытаюсь встретиться с ними должным образом, но проблемы остаются. Нужно ли как-то "распределять" память? (Я уверен, что мне нужно освободиться после того, как я получу данные).

Это в Windows 7 с 32-битным Python 2.7.

Я просмотрел другие подобные проблемы и не нашел решения. Мне интересно, могу ли я на данный момент винить API в этой проблеме.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Работа с указателями и массивами объясняется в [Python 3]: преобразования типов .

Я подготовил для тебя фиктивный пример.

main.c

#if defined(_WIN32)
#  define DECLSPEC_DLLEXPORT __declspec(dllexport)
#else
#  define DECLSPEC_DLLEXPORT
#endif


static int kSize = 5;


DECLSPEC_DLLEXPORT int size() {
    return kSize;
}


DECLSPEC_DLLEXPORT int function(int dummy, float *data1, float *data2) {
    for (int i = 0; i < kSize; i++) {
        data1[i] = dummy * i;
        data2[i] = -dummy * (i + 1);
    }
    return 0;
}

code.py

#!/usr/bin/env python

import sys
import ctypes


c_float_p = ctypes.POINTER(ctypes.c_float)


def main():
    dll_dll = ctypes.CDLL("./dll.so")

    size_func = dll_dll.size
    size_func.argtypes = []
    size_func.restype = ctypes.c_int


    function_func = dll_dll.function
    function_func.argtypes = [ctypes.c_int, c_float_p, c_float_p]
    function_func.restype = ctypes.c_int

    size = size_func()
    print(size)

    data1 = (ctypes.c_float * size)()
    data2 = (ctypes.c_float * size)()

    res = function_func(1, ctypes.cast(data1, c_float_p), ctypes.cast(data2, c_float_p))
    for i in range(size):
        print(data1[i], data2[i])


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Примечания

  • Часть C пытается имитировать то, что делает ваш .dll (или, по крайней мере, то, что я понял):
    • размер - получает размеры массивов
    • function - заполняет массивы (до их размера - при условии, что они были правильно распределены вызывающей стороной)
  • Python часть проста:
    • Загрузить .dll
    • Определите argtypes и restype (в вашем коде это restype ' s ) для 2 функций (для size_func необязательно)
    • Получить длину
    • Инициализировать массивы
    • Передайте их function_func , используя ctypes.cast

Вывод (на Lnx , поскольку сборка кода C намного проще, но работает и на Win ):

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050043861]> gcc -shared -o dll.so main.c
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050043861]> python3 code.py
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux

5
0.0 -1.0
1.0 -2.0
2.0 -3.0
3.0 -4.0
4.0 -5.0
0 голосов
/ 26 апреля 2018

Это действительно зависит от того, что вы делаете с этими указателями с плавающей точкой.

Если вы пытаетесь пройти это, то есть

for(int i = 0; i < size; i++)
    printf("%f\n%, data1[i])

тогда наверняка это проблематично, так как массив не был выделен. Вы просто передали указатель, указывающий на число с плавающей точкой. Это все.

Вы должны сначала выделить эту память. С этой целью Попытка 4 выглядит более многообещающей, но я подозреваю, что у вас есть проблема внутри вашей функции C, приводящая к сбою.

Трудно сказать, не видя реализации этой функции.

...