2014-12-19 2 views
3

Недавно я попытался написать mexfunctions с использованием структурных переменных. Я смотрел учебник, но запутался из-за того, как передаются значения переменных. В следующем примере (mexfunction_using_ex_wrong.m & mexfunction_using_ex_wrong.cpp) показано, как получить переменные, переданные из matlab в mexfunction. Тем не менее, в этом случае результат:Ошибка переменных mexfunction в массиве структурной переменной

address i_c1=2067094464 i_c2=2067094464 
     i_c1=10   i_c2=10 
address i_c1=1327990656 i_c2=2067100736 
     i_c1=2   i_c2=20 
address i_c1=2067101056 i_c2=2067063424 
     i_c1=3   i_c2=30 

Как можно видеть, первый элемент массива c2 переменной структуры с1 & является случайно то же самое.

Но в другом примере (mexfunction_using_ex_correct.m & mexfunction_using_ex_correct.cpp) элементы массива 1 (b1) и массива 2 (b2) структурной переменной не связаны, как я ожидаю. Результат:

address i_b1=1978456576 i_b2=1326968576 
     i_b1=1   i_b2=10 
address i_b1=1978456584 i_b2=1326968584 
     i_b1=2   i_b2=20 
address i_b1=1978456592 i_b2=1326968592 
     i_b1=3   i_b2=30 

Однако, это более распространено использование 1-й пример в программировании. так может кто-нибудь объяснить, почему в 1-м примере адреса i_c1 & i_c2 совпадают?

Следующий код mexfunction_using_ex_wrong.m

clc 
clear all 
close all 

mex mexfunction_using_ex_c_wrong.cpp; 

a.b(1).c1=double(1); 
a.b(2).c1=double(2); 
a.b(3).c1=double(3); 

a.b(1).c2=double(1); 
a.b(2).c2=double(2); 
a.b(3).c2=double(3); 

mexfunction_using_ex_c_wrong(a); 

Следующий код mexfunction_using_ex_c_wrong.cpp

#include "mex.h" 

void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]) 
{ 
    int i, j, k; 

    double *i_c1; 
    double *i_c2; 

    // for struct variables(pointers) inside fcwcontext 
    mxArray *mx_b, *mx_c1, *mx_c2;  

    mx_b=mxGetField(prhs[0], 0, "b"); 

    for(i = 0;i < 3;i=i+1) 
    {    
     mx_c1=mxGetField(mx_b, i, "c1"); 
     mx_c2=mxGetField(mx_b, i, "c2"); 

     i_c1=mxGetPr(mx_c1); 
     i_c2=mxGetPr(mx_c2);   

     *i_c2=(*i_c2)*10; 

     printf("address i_c1=%d i_c2=%d\n", i_c1, i_c2); 
     printf(" i_c1=%g i_c2=%g\n", *i_c1, *i_c2);    
    }     
} 

Следующий код mexfunction_using_ex_c_correct.m

clc 
clear all 
close all 

mex mexfunction_using_ex_correct.cpp; 

a.b1(1)=double(1); 
a.b1(2)=double(2); 
a.b1(3)=double(3); 

a.b2(1)=double(1); 
a.b2(2)=double(2); 
a.b2(3)=double(3); 

mexfunction_using_ex_correct(a); 

Следующий код mexfunction_using_ex_c_correct.cpp

#include "mex.h" 

void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]) 
{ 
    int i, j, k; 

    double *i_b1; 
    double *i_b2; 

    mxArray *mx_b1, *mx_b2;  

    mx_b1=mxGetField(prhs[0], 0, "b1"); 
    mx_b2=mxGetField(prhs[0], 0, "b2"); 

    for(i = 0;i < 3;i=i+1) 
    {      
     i_b1=mxGetPr(mx_b1); 
     i_b2=mxGetPr(mx_b2);   

     i_b2[i]=i_b2[i]*10; 

     printf("address i_b1=%d i_b2=%d\n", &i_b1[i], &i_b2[i]); 
     printf(" i_b1=%g i_b2=%g\n", i_b1[i], i_b2[i]);     
    }     
} 

ответ

1

адреса не являются «случайно то же самое» - они намеренно же, из-за внутренних оптимизаций MATLAB копии при записи. Если вы посмотрите на документацию MEX, вы увидите предупреждения разбросаны вокруг ...

Do not modify any prhs values in your MEX-file. Changing the data in these read-only mxArrays can produce undesired side effects.

... в различных формах ...

Note Inputs to a MEX-file are constant read-only mxArrays. Do not modify the inputs. Using mxSetCell* or mxSetField* functions to modify the cells or fields of a MATLAB® argument causes unpredictable results.

... пытаясь сделать это очень ясно, что вы должны абсолютно ничего не изменять. в качестве ввода. Вызывая mxGetPr() на входные данные и записывая обратно на этот указатель, как и в случае с i_b2 и i_c2, вы попадаете прямо в эту территорию с «непредсказуемыми результатами» - если вы посмотрите на a.b(1).c1 в рабочем пространстве MATLAB после вызова, это будет действительно быть 10, даже если вы «только» изменили c2.

От MEX, вы смотрите на сырье хранения данных без каких-либо знаний, доступа к ним, внутреннему ведению домашнего хозяйству MATLAB, поэтому единственный безопасного способ изменить что-либо использовать mxCreate* или mxDuplicate* функции, чтобы получить ваш собственные безопасные массивы, вы можете делать все, что хотите, и переходить обратно в MATLAB через plhs.

Это говорит о том, что я допустил злоупотребление in-place modification для получения значительного прироста производительности в одном случае, где я мог гарантировать, что мои данные были уникальными и не разделенными, но это в лучшем случае не поддерживается и в худшем случае опасно.

+2

Благодарим вас за ответ. Я, наконец, решу эту проблему. [Ответ] (http://www.mathworks.com/matlabcentral/answers/uploaded_files/1487/mxsharedcopy.c) полностью решает мою проблему с очень полезной функцией mxCreateSharedDataCopy(). Однако эта функция является недокументированной функцией, которую можно вызывать только в Matlab 2014, если файл является .c. Если этот файл является .cpp, компоновщик не смог его найти. Сообщение об ошибке - ошибка LNK2019: внешний символ неразрешен «struct mxArray_tag * __cdecl mxCreateSharedDataCopy (struct mxArray_tag const *)». –

+0

Я бы действительно, ** сильно ** рекомендую не делать этого - используйте 'mxDuplicateArray', измените _that_ copy, а затем передайте его через' plhs'. Узнайте, как использовать MEX _properly_ и обходитесь с ним, даже не задумываясь о том, как справляться с неподдерживаемыми хаками и недокументированными деталями реализации. Если (как и в моем случае) хак экономит около часа и половины времени работы в день во время разработки, то, возможно, это стоит риска; Для обучения это ужасная идея. – Notlikethat

Смежные вопросы