Получение ошибок распределения памяти при запуске скомпилированной версии следующего кода. Это приложение, в котором определена структура указателей, и я хотел бы присвоить значение указателю, а затем передать эту структуру в c-код. Я видел другие примеры и вопросы по этому вопросу, и я считаю, что это делается правильно, однако все еще возникают проблемы.
Код будет компилироваться отлично, однако он запускает Python при его запуске. Отладка с помощью Visual Studio показывает нарушение доступа к памяти. Я исследовал это совсем немного, но не могу придумать, почему это происходит. Был способен воспроизвести это на другом компьютере.
Я считаю, что это имеет какое-то отношение к тому, как struct test_M
выделяется и ссылается на стек. Я пробовал несколько разных вариантов определения test_M.param.gain_val, показанный код позволяет компилировать код, и я могу получить вывод для печати на экране. Однако после этого Python аварийно завершает работу.
К сожалению, я не могу изменить код c, потому что это автоматически сгенерированный код из встроенного кодера Matlab/Simulink.
Любая помощь будет оценена по достоинству.
Using:
python = 3.6
cython = 0.26
numpy = 1.13.1
Visual Studio 2017 v15
ccodetest.c
#include <stdlib.h>
typedef struct P_T_ P_T;
typedef struct tag_T RT_MODEL_T;
struct P_T_ {
double gain_val;
};
struct tag_T {
P_T *param;
};
void compute(double array_in[4], RT_MODEL_T *const test_M)
{
P_T *test_P = ((P_T *) test_M->param);
int size;
size = sizeof(array_in);
int i;
for (i=0; i<size; i++)
{
array_in[i] = array_in[i] * test_P->gain_val;
}
}
cython_param_test.pyx
cimport cython
import numpy as np
cimport numpy as np
from cpython.mem cimport PyMem_Malloc, PyMem_Free
np.import_array()
cdef extern from "ccodetest.c":
ctypedef tag_T RT_MODEL_T
ctypedef P_T_ P_T
cdef struct P_T_:
double gain_val
cdef struct tag_T:
P_T *param
void compute(double array_in[4], RT_MODEL_T *const test_M)
cdef double array_in[4]
def run(
np.ndarray[np.double_t, ndim=1, mode='c'] x_in,
np.ndarray[np.double_t, ndim=2, mode='c'] x_out,
np.ndarray[np.double_t, ndim=1, mode='c'] gain):
cdef RT_MODEL_T* test_M = <RT_MODEL_T*> PyMem_Malloc(sizeof(RT_MODEL_T))
global array_in
test_M.param.gain_val = <double>gain
cdef int idx
try:
for idx in range(len(x_in)):
array_in[idx] = x_in[idx]
compute(array_in, test_M)
for idx in range(len(x_in)):
x_out[idx] = array_in[idx]
finally:
PyMem_Free(test_M)
return None
setup.py
import numpy
from Cython.Distutils import build_ext
def configuration(parent_package='', top_path=None):
from numpy.distutils.misc_util import Configuration
config = Configuration('', parent_package, top_path)
config.add_extension('cython_param_test',
sources=['cython_param_test.pyx'],
# libraries=['m'],
depends=['ccodetest.c'],
include_dirs=[numpy.get_include()])
return config
if __name__ == '__main__':
params = configuration(top_path='').todict()
params['cmdclass'] = dict(build_ext=build_ext)
setup(**params)
run_cython_param_test.py
import cython_param_test
import numpy as np
n_samples = 4
x_in = np.arange(n_samples, dtype='double') % 4
x_out = np.empty((n_samples, 1))
gain = np.ones(1, dtype='double') * 5
cython_param_test.run(x_in, x_out, gain)
print(x_out)
cdef RT_MODEL_T* test_M = <RT_MODEL_T*> PyMem_Malloc(sizeof(RT_MODEL_T))
Вы выделяете место для RT_MODEL_T
. test_M
имеет один элемент, указатель на P_T
. Выделение пространства для RT_MODEL_T
выделяет пространство для хранения указателя - он не выделяет P_T
на который указывает. Там, где param
точки полностью произвольны в данный момент и, скорее всего, это адрес памяти, на который вам не разрешено писать.
test_M.param.gain_val = ...
Вы P_T
записать элемент P_T
на P_T
указывает param
. Однако param
не указывает на выделенный P_T
.
... = <double>gain
Вы пытаетесь сделать массив numpy двойным. Это не имеет никакого смысла. Вероятно, вы хотите получить первый элемент массива numpy, или вы должны передать gain
как просто двойной, а не многомерный массив парных чисел?
Поскольку test_M
и его содержимое не должны жить за пределами функции, в которую они выделены, у меня возникнет соблазн выделить их в стеке, и таким образом вы сможете полностью избежать malloc
и free
:
cdef RT_MODEL_T test_M # not a pointer
cdef P_T p_t_instance
p_t_instance.gain_val = gain # or gain[0]?
test_M.param = &p_t_instance
# ...
compute(array_in, &test_M) # pass the address of 'test_M'
Только делайте это, если вы уверены в требуемом времени жизни test_M
и P_T
котором есть указатель.