1D и 2D C массивы, массивы CTypes и NumPy: как конвертировать между ними - PullRequest
0 голосов
/ 19 ноября 2018

У меня есть некоторые функции, написанные на C, которые я хочу вызывать из Python, используя ctypes.Преобразование базовых типов данных Python в типы данных C, такие как int, float, double и т. Д. С помощью ctypes, довольно легко, но когда дело доходит до массивов, у меня возникают некоторые проблемы.

Насколько я знаю, есть 3 "формы«из массивов.В объявлениях функций вы можете объявить эти формы несколькими способами.Для простоты давайте взглянем на целочисленные массивы.

1D Массив целых чисел в C

1-мерный массив часто объявляется и инициализируется следующим образом:

int foo[5] = {1, 2, 3, 4, 5];

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

void func(int foo[5], int len);
void func(int foo[], int len);
void func(int *foo, int len);

1D Массив целочисленных указателей в C

Эти массивы часто путают с 2D-массивами AFAIK.Но они разные.Это массивы, которые содержат указатели.Таким образом, массив, который содержит адреса памяти целочисленных переменных в нашем примере.Они объявлены так:

int *foo[5];

Это массив из 5 указателей int.НЕ указатель на массив из 5 дюймов ... В объявлении функции они выглядят так:

void func(int *foo[5], int len);
void func(int *foo[], int len);
void func(int **foo, int len);

2D-массив целых чисел в C

2D-массив объявляется так:

int foo[2][5];

В объявлениях функций они выглядят так:

void func(int foo[2][5], int rows, int columns);
void func(int foo[][5], int rows, int columns);
void func(int (*foo)[5], int rows, int columns);
void func(int *foo, int rows, int columns);

В последнем объявлении вы даете адрес памяти первого элемента foo [0], например: &foo[0][0]или foo[0] и вам действительно нужно дать и строки, и столбцы!

Вопросы

Теперь мои вопросы:

  1. Как следует ctypes.argtypesвыглядеть для каждой из этих 3 форм массива?
  2. Как создать и преобразовать массив NumPy в формат ctypes для каждой из этих трех форм массива?
  3. Как преобразовать каждый из этих трех массивов массивов типа ctype обратно в массивы NumPy?

1) Я предполагаю, что свойство ctypes.argtypes для каждой формы выглядит следующим образом:

  • 1D массив целых чисел: ctypes.POINTER(ctypes.c_int)
  • 1D массив целочисленных указателей: ctypes.POINTER(ctypes.POINTER(ctypes.c_int)) и ctypes.POINTER(ctypes.c_int) * 5 в случае int *foo[5]?
  • 2D массив целых чисел: в случае int (*foo)[5]: ctypes.POINTER(ctypes.c_int * 5) И в случае int foo[2][5]: (ctypes.c_int*5)*2 В случае int *foo: ctypes.POINTER(ctypes.c_int)

2) Я прочитал, что могу использовать атрибут ctypes numpy.ndarrayМетод data_as для преобразования массива Numpy в определенный формат ctypes?Поэтому, учитывая мой массив форм:

1D Целочисленный массив:

data = numpy.array([[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]])
ctypes_format = data.ctypes.data_as(ctypes.POINTER(ctype.c_int))

1D Целочисленный массив указателей

data = numpy.array([[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]])
ctypes_format = data.ctypes.data_as(ctypes.POINTER(ctypes.POINTER(ctype.c_int)))

Я не уверен, что это правильно ...

2D Integer Array

data = numpy.array([[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]])
data.ctypes.data_as(ctypes.POINTER(ctype.c_int))

Или в случае (*foo)[5]:

data = numpy.array([[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]])
data.ctypes.data_as(ctypes.POINTER(ctypes.c_int * 5))

Также не уверен, что это правильно

3) Теперь мой последний вопрос - как я могу преобразовать эти массивы C / ctypes обратно в массивы NumPy.Я действительно понятия не имею ...

...