#python #c #c #ctypes
#python #c #c #ctypes
Вопрос:
Я использую ctypes
для преобразования некоторой информации в двоичный файл, который должен быть прочитан программой на C . Этот файл будет содержать строки со строками и другие строки с double / vectors of double .
Проблемы возникают, когда я пытаюсь прочитать вектор double в C : адрес вектора идет в конец строки, и адрес имеет 11 символов, а в C имеет 8 символов. Когда я пытаюсь напрямую прочитать вектор в C , возникает ошибка из-за этой разницы.
Возможным решением было бы читать элемент за элементом вектора, но это будет стоить производительности.
Есть ли какая-либо возможность скопировать адрес во время преобразования и чтения или проигнорировать его и весь вектор сразу?
Вот некоторый код, который мы сделали для тестирования:
C DLL модуль:
#include<iostream>
#include<fstream>
#include<cstring>
#include <typeinfo>
using namespace std;
#define DLLEXPORT extern "C" __declspec(dllexport)
struct new_element {
int id;
unsigned int n_measures;
double* value;
};
DLLEXPORT int writer_bin_file_c(const char* file_path, new_element structed_data)
{
try {
ofstream output_file(file_path);
output_file.write((char*)amp;structed_data, sizeof(structed_data));
output_file << amp;structed_data;
output_file.close();
} catch (...) {
return -1;
}
return 0;
}
DLLEXPORT new_element reader_bin_file_c(const char* file_path, new_element structed_data)
{
try {
ifstream input_file(file_path, ios::binary);
input_file.read((char*)amp;structed_data, sizeof(structed_data));
input_file.close();
} catch (...) {
cout << "Error ao ler o arquivo" << endl;
}
return structed_data;
}
Запись файла на Python:
from ctypes import *
import sys
import numpy as np
lib = CDLL("version4/template_file.so")
class new_element(Structure):
_fields_ = [("id", c_int),
("n_measures", c_uint),
("value", POINTER(c_double))]
template_file = lib
new_element_pointer = POINTER(new_element)
writer_bin_file = template_file.writer_bin_file_c
writer_bin_file.argtypes = [c_char_p, new_element]
writer_bin_file.restype = c_void_p
reader_bin_file_c = template_file.reader_bin_file_c
reader_bin_file_c.restype = new_element
tam = 10
medida = np.arange(tam, dtype=c_double)
medida = medida.ctypes.data_as(POINTER(c_double))
element = new_element(4, tam)
element.value = medida
file_out = b'version4/element.txt'
answer = writer_bin_file(file_out, element)
C чтение файла:
#include<iostream>
#include<fstream>
#include<cstring>
#include <typeinfo>
using namespace std;
struct new_element {
int id;
unsigned int n_measures;
double* value;
};
new_element reader_bin_file(const char* file_path, new_element structed_data)
{
try {
ifstream input_file(file_path);
input_file.read((char*)amp;structed_data, sizeof(structed_data));
input_file.close();
} catch (...) {
cout << "Error ao ler o arquivo" << endl;
}
return structed_data;
}
int main(int argc, char const *argv[])
{
new_element read_template;
read_template = reader_bin_file(file_out, read_template);
cout << "ID: " << read_template.id << endl;
cout << "n_measures: " << read_template.n_measures << endl;
cout << "Value: ";
for (int i = 0; i < read_template.n_measures; i )
{
cout << "( " << i << " ): " << read_template.value[i] << " | ";
}
cout << endl;
return 0;
}
Комментарии:
1. Начните с открытия ваших файлов в двоичном режиме; будет иметь значение, если вы используете Windows, хорошая практика на других ОС.
2. Спасибо, я забыл!
Ответ №1:
Здесь у вас одно глубокое недоразумение.
Пара полей
unsigned int n_measures;
double* value;
это массив (выводимый из их имен), поэтому в writer вам нужно сохранить n_measures
двойное значение, а не один указатель. Следовательно, в программе чтения вы должны считывать n_measures
значения, а не просто указатель. Указатель — это просто индекс в области памяти, а не какая-то «всемогущая» функция языка C / C , которая сохраняет все, что вам нужно.
Итак, в вашем коде для написания C выполните
DLLEXPORT int writer_bin_file_c(const char* file_path, new_element structed_data)
{
try {
ofstream output_file(file_path);
output_file.write((char*)amp;structed_data.id, sizeof(int));
output_file.write((char*)amp;structed_data.n_measures, sizeof(int));
// write out all the elements one by one, not just the pointer
for (int i = 0 ; i < structed_data.n_measures ; i )
output_file.write((char *)amp;structed_data[i], sizeof(double));
output_file.close();
} catch (...) {
return -1;
}
return 0;
}
Надеюсь, вы поняли идею, по крайней мере, в части C . Код считывателя аналогичен — считывает id
, n_measures
а затем выделяет values
массив и считывает значения одно за другим.
Комментарии:
1. Я попробую это и скоро дам вам отзыв, спасибо за ваш ответ.
2. Мы сделали подобный подход, с некоторыми изменениями в реальном коде, и мы его получаем. Спасибо, чувак!