Сложность возврата поплавка из Ctypes - PullRequest
0 голосов
/ 21 марта 2020

В настоящее время я пытаюсь написать простую оболочку для некоторого кода C ++, чтобы иметь возможность передавать некоторые данные сигнала, выполнять операции с графическим процессором и отправлять их обратно. На данный момент я вырезал все элементы графического процессора, потому что у меня возникают проблемы с получением ctypes для возврата чего-либо, кроме целого числа.

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

extern "C" float* giveLotsZeroes(int length) {
    float* list2 = (float*)malloc(sizeof(float)*length);
    for (unsigned int i = 0; i < length; i++) list2[i] = 0;
    return list2;
}

Это одна из моих примеров функций C ++, которые я использовал для проверки функциональности возврата поплавков в файле "kernal.cu". Он передается в C с extern float* giveLotsZeroes(int length); и __declspec(dllexport) float* giveLotsOfZeroes(int length);, определенными в "chead.h" (обратите внимание на Of в середине имени функции, чтобы различать их). Наконец, float* giveLotsOfZeroes(int length) { return giveLotsZeroes(length); } определено в Source. c, который включает chead.h, и у компоновщика, похоже, нет проблем с компиляцией этого в многопоточную dll. У меня есть подобная итерация этого, которая возвращает список нулей в виде целых чисел, который прекрасно функционирует, настолько, что я реализовал его в обработке ошибок графического процессора, и с каждой отдельной строкой кода графического процессора, по-видимому, вызывающей ошибку, у меня есть причина полагать, что реализация обработки ошибок работает нормально, за исключением, о котором я расскажу позже.

При попытке вернуть список целых чисел длиной 128 я использовал библиотеку ctypeslib numpy с большим успехом, с

accelerator.getLastErrorCode.restype = np.ctypeslib.ndpointer(dtype=ctypes.c_int,shape=(128,))
accelerator.getLastLineExecuted.restype = np.ctypeslib.ndpointer(dtype=ctypes.c_int,shape=(128,))

, и это прекрасно работает, однако, если я замените 128 моей переменной длины "length" и ctypes.c_int на ctypes.c_float, python возвращает одно целое число, обычно где-то между 1e8 и 1e10. С такими странными результатами я попытался вернуть одинарные числа с плавающей запятой, что дало аналогичные результаты, хотя можно было бы предположить менее вопиюще, поскольку функция с одним значением также возвращала одно значение. Интересно, что когда я использую метод определения рестайпов np.ctypeslib.ndpointer, функция python type по-прежнему утверждает, что результатом является numpy.ndarray, но будет жаловаться, если вы относитесь к нему как к одному. В качестве альтернативы я попытался определить restypes этой функции или ее варианты как ctypes.c_float*length или ctypes.POINTER(ctypes.c_float*length), но безуспешно.

Фактически, я сделал две функции, которые возвращают единичные нули тот, который возвратил его из C ++ в C в python, и тот, который сделал это прямо из C, и заставил их обоих вывести свои нули на консоль, чтобы подтвердить, что ни у C не было проблем, ни C имел проблему с нулем в C ++, но к тому времени, когда они достигли python, ноль C стал равным 1 (что я позже обнаружил, независимо от того, что C пытался вернуть) и Ноль в C ++ стал непротиворечивым 164. Друг порекомендовал изменить каждый экземпляр 0 на 0.0f, что изменило 164 на стандартное случайное большое число.

Единственная проблема, с которой я столкнулся при обработке ошибок , сказав, что я доберусь до этого позже, заключается в том, что в одном единственном, но повторяемом нечетном случае 700 удалось выйти из функции, которая должна была быть только в состоянии вернуть число от 0 до 29. Не уверен, какая возможная связь может иметь другие ошибки, но если это помогает, это помогает.

Я включил свой код в следующую вставку, но обратите внимание на большие разделы код python - это просто тесты того, что работает как ожидалось, а что нет.

https://pastebin.com/j7gfiKA6

1 Ответ

0 голосов
/ 24 марта 2020

Ваши возвращаемые значения ctypes.POINTER(ctypes.c_float):

>>> from ctypes import *
>>> dll = CDLL('test')
>>> dll.giveLotsZeroes.argtypes = c_int,
>>> dll.giveLotsZeroes.restype = POINTER(c_float)
>>> x = dll.giveLotsZeroes(100)
>>> x
<__main__.LP_c_float object at 0x0000022DE407F948>
>>> x[0]
0.0
>>> x[99]
0.0

Вы также можете получить весь массив с проверкой границ с помощью:

>>> a = cast(x,POINTER(c_float*100)).contents
>>> a
<__main__.c_float_Array_100 object at 0x0000022DE45A5CC8>
>>> a[0]
0.0
>>> a[99]
0.0
>>> a[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: invalid index

Преобразовать в список Python:

>>> list(a)
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
...