Вопрос или проблема
Я хочу перенести данные из Python в библиотеку C++ DLL для работы с матрицами, а затем получить данные обратно. Я создаю массив (c_double * 102)(c_double(0)) в Python (первый и второй элементы массива говорят о размере матрицы).
В Python у меня есть правильные данные (проверено с помощью более простой функции, такой как сумма членов массивов и возврат этой суммы), но когда я пытаюсь заполнить матрицу, она всегда заполняется нулями.
(код на Python):
В Python у меня есть класс, который переводит список (list()) в (c_types * 102)(0) для соединения с моей DLL, и это вроде работает правильно. Также я использую указатели для передачи данных.
class tu_matrix:
body = (c_double * 102)(c_double(0))
ptr = POINTER(c_double * 102)
def load(self, data = list(list())):
self.data = data
self.n_size = len(data)
self.m_size = len(data[0])
for i in range(self.n_size):
for j in range(self.m_size):
self.body[2+i*self.m_size + j] = c_double(data[i][j])
ptr = pointer(self.body)
def calcMatrix():
tu_matrix1.load(matrix1)
tu_matrix2.load(matrix2)
# Аргументы для matrix_sum
matrix_lib.matrix_sum.argtypes = [POINTER(c_double * 102),
POINTER(c_double * 102)]
# Тип возвращаемого значения matrix_sum
matrix_lib.matrix_sum.restype = POINTER(c_double * 102)
# Получение указателей на массивы
ptr1 = pointer(tu_matrix1.send()) # указатель на первый массив
ptr2 = pointer(tu_matrix2.send()) # указатель на второй массив
# Вызов функции, передающей массивы
result_ptr = matrix_lib.matrix_sum(ptr1, ptr2)
result_array = result_ptr.contents # получение содержимого из указателя
# перевод в список
list_of_lists = []
for i in range(0, 102, 10):
sublist = [result_array[i + j] for j in range(10) if i + j < 102]
list_of_lists.append(sublist)
print(list_of_lists)
return result_ptr
(функция для преобразования данных):
В моем C++ коде я заполняю вектор данными из Python и в этот момент ловлю ошибку с некорректными данными. Все заполнено нулями, когда я пробую использовать, я думаю, что проблема связана с личным классом, потому что простые массивы или типы данных работают нормально.
template<typename val_type>
void matrix<val_type>::arr_to_matrix(double arr[102]) {
this->body.clear();
for (int i = 0; i < (int)arr[0]; i++) {
vector<double> line;
for (int j = 0; j < (int)arr[1]; j++) {
line.push_back(arr[2 + i * (int)arr[1] + j]);
}
this->body.push_back(line);
}
this->size_n = (int)arr[0];
this->size_m = (int)arr[1];
this->empty_matrix = false;
this->zero_matrix = false;
this->was_calc_det = false;
}
(функция dll):
static double result[102];
extern "C" __declspec(dllexport) double* matrix_sum(double arr1[102], double arr2[102]) {
// Сумма матриц для данных c-types от Python
matrix<double> m1({ { 1,1 }, { 2,2 } });
matrix<double> m2({ { 1,1 }, { 2,2 } });
m1.arr_to_matrix(arr1);
m2.arr_to_matrix(arr2);
m1 += m2;
int n = m1.line_size();
int m = m1.column_size();
result[0] = n;
result[1] = m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
result[2 + i * m + j] = m1.val(i, j);
}
}
return result;
}
Если я удалю строки m1.arr_to_matrix(arr1); m2.arr_to_matrix(arr2);
, то он инициализируется с помощью initlist и работает правильно, но в этом случае теряется весь смысл создания интерфейса с Python. Когда я запускаю программу без Python и проверяю, она работает корректно:
(это работает)
int main () {
double* arr1 = new double[102];
double* arr2 = new double[102];
for (int i=0; i<6; i++) {
arr1[i] = 2;
arr2[i] = 2;
}
arr1 = matrix_sum(arr1, arr2);
for (int i = 0; i<6; i++) {
std::cout << arr1[i] << " ";
}
}
Ответ или решение
Для успешной инициализации данных c Python в библиотеку C++ через DLL с использованием ctypes
, необходимо учесть несколько ключевых моментов. Рассмотрим предоставленный код более подробно и выявим возможные причины возникновения проблемы с заполнением массива нулями.
1. Структура класса tu_matrix
Класс tu_matrix
, который вы создали, корректно инициализирует массив размером 102. Однако есть некоторые моменты, которые стоит улучшить:
class tu_matrix:
body = (c_double * 102)(c_double(0))
ptr = POINTER(c_double * 102)
def load(self, data=list(list())):
self.n_size = len(data)
self.m_size = len(data[0])
for i in range(self.n_size):
for j in range(self.m_size):
self.body[2 + i * self.m_size + j] = c_double(data[i][j])
def send(self):
return pointer(self.body)
Убедитесь, что метод send
, который вы используете для передачи указателя, возвращает корректный указатель на вашу структуру. Рекомендуется переопределить метод send
для лучшего понимания.
2. Передача указателей в функцию matrix_sum
В функции calcMatrix
есть небольшая ошибка при передаче указателей. Вам не нужно вызывать pointer
от уже созданного указателя:
ptr1 = pointer(self.body)
ptr2 = pointer(self.body)
Обновите вызов функции, чтобы передать указатели непосредственно.
3. Вызов функции в C++
В коде C++ функция matrix_sum
ожидает массивы, переданные из Python. Убедитесь, что вы правильно обрабатываете полученные данные:
extern "C" __declspec(dllexport) double* matrix_sum(double arr1[102], double arr2[102]) {
matrix<double> m1, m2;
m1.arr_to_matrix(arr1);
m2.arr_to_matrix(arr2);
// Производим сложение матриц
m1 += m2;
// Установка результатов
result[0] = m1.line_size();
result[1] = m1.column_size();
for (int i = 0; i < m1.line_size(); i++) {
for (int j = 0; j < m1.column_size(); j++) {
result[2 + i * m1.column_size() + j] = m1.val(i, j);
}
}
return result;
}
4. Проверка на ошибки
Когда вы работаете с памятью и указателями, важно отлаживать код на наличие возможных ошибок. Рекомендуется добавлять отладочные сообщения (например, printf
или std::cout
) для проверки содержимого массивов, прежде чем использовать их. Это поможет выявить проблему на ранней стадии.
5. Заключение
Если вы всё еще получаете нулевые значения, проверьте следующие моменты:
- Убедитесь, что массив правильно инициализируется и заполняется перед передачей в C++.
- Проверьте соответствие типов данных между Python и C++. Например, в Python
c_double
должен соответствоватьdouble
в C++. - Убедитесь, что передача указателей происходит корректно, и данные не теряются в процессе передачи.
Если все вышеперечисленное выполнено, ваша функция должна работать корректно и возвращать ожидаемые результаты. Не забывайте также тестировать все ключевые части кода по отдельности для изоляции потенциальных ошибок.