Matlab Engine for C - Passing Arrays

조회 수: 4(최근 30일)
Arwel
Arwel 2017년 7월 19일
편집: James Tursa 2017년 7월 20일
Hi, I am trying to make a simple Matlab Engine app, and am running into difficulties working out how to pass arrays. The code is as follows....
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
void myFun(double t2[], int arrayLen, char *funName);
void myFun(double t2[], int arrayLen, char *funName) {
static Engine *ep;
static double engStatus = 0;
mxArray *result = NULL;
double * sum;
mxArray *T = NULL;
//char funName[50] = "debugMfile";
if(engStatus == 0) {
ep = engOpen(""); // Connect to MATLAB engine
if(ep==0) {
printf("Connecton to Matlab Engine failed\n");
}
else {
printf("Connecton to Matlab Engine succeeded!\n");
engEvalString(ep,"cd('/home/arwel/Documents/MATLAB/mNestFiles');");
engStatus = 1;
}
}
//Create variables for the inputs
T = mxCreateDoubleMatrix(1,arrayLen,mxREAL);
memcpy((void *)mxGetPr(T), (void *)t2, 4);
//Put these variables in the Matlab workspace
engPutVariable(ep,"time",T);
//Now call the function..
//(N.B. eventually aim to do this based on 'funName')
engEvalString(ep,"total = debugMfile(time)");
//Get the return value..
result = engGetVariable(ep,"total");
sum = (double *)mxGetData(result);
printf("The answer is %f \n",sum);
engClose(ep);
}
int main() {
double time[4] = {1, 2, 3, 4};
int arrayLen = 4;
char funName[50] = "debugMfile";
myFun(time, arrayLen, funName);
return(0);
}
..with a 'toy' Matlab test function that looks like this...
function total = debugMfile(time)
total = sum(time);
save debugMfileVars.mat
end
But, the result I get back into C is always 0.000, and if I examine 'debugMfileVars.mat' it's just...
>> a = load('debugMfileVars.mat')
a =
struct with fields:
time: [0 0 0 0]
total: 0
>>
Clearly I've missed a step or mixed up something with pointers here somewhere but can't spot it. What have I missed here?? Cheers, Arwel

답변(4개)

Jan
Jan 2017년 7월 19일
편집: Jan 2017년 7월 19일
You do not want to display the pointer, but its contents:
double * sum;
sum = (double *)mxGetData(result);
printf("The answer is %f \n", *sum);
// ^
You do not want to copy 4 bytes, but 4 doubles:
memcpy((void *)mxGetPr(T), (void *)t2, 4 * sizeof(double))
// ^^^^^^^^^^^^^^^^

James Tursa
James Tursa 2017년 7월 19일
편집: James Tursa 2017년 7월 19일
In addition to what Jan has written, you will want to destroy the mxArray variables after using them in myFun so you don't have a memory leak. And since this is an Engine app and not a mex routine, you should check to see that those mxArray pointers are not NULL before you use them. E.g.,
//Create variables for the inputs
T = mxCreateDoubleMatrix(1,arrayLen,mxREAL);
if( T ) {
memcpy( mxGetPr(T), t2, arrayLen*sizeof(*t2) );
} else {
/* do something to handle error */
}
//Put these variables in the Matlab workspace
engPutVariable(ep,"time",T);
mxDestroyArray(T);
//Now call the function..
//(N.B. eventually aim to do this based on 'funName')
engEvalString(ep,"total = debugMfile(time)");
//Get the return value..
result = engGetVariable(ep,"total");
if( result ) {
/* should add code here to check result for correct class and size etc */
sum = (double *)mxGetData(result);
} else {
/* do something to handle error */
}
printf("The answer is %f \n",*sum);
mxDestroyArray(result);

Arwel
Arwel 2017년 7월 20일
Awesome, thanks guys! :)

Arwel
Arwel 2017년 7월 20일
James, I just noticed something. You removed the (void *) from the memcpy call in your code snippet. I only put it there because it's in mathworks own engDemo.c example, but not being very good with C I'm not all that sure what it means to be honest. Could you maybe expand a little on what it's supposed to do, why it's not necessary here, and when it might be needed? Cheers, Arwel
  댓글 수: 1
James Tursa
James Tursa 2017년 7월 20일
In C (and by default in C++), all function arguments are passed by value. So anything in the argument list that doesn't match the signature exactly will be converted to the exact signature type first and then that is what is actually passed to the function ... a copy (or converted copy) of the value. This all happens automatically as part of the compiling process. Some conversions (like int to double) can be done with no problem, but other conversions (like double to int pointer) cannot be done and will cause a compile error. But the compiler will always attempt to do the conversion automatically if it can (and it is allowed by the language).
The signature for memcpy is:
void *memcpy(void *str1, const void *str2, size_t n)
Object pointers passed into those 1st & 2nd arguments will get automatically converted to void pointers. Btw the same would be true even if I directly assigned an object pointer to a variable that was of type void pointer ... the conversion happens automatically. Since you get the conversion that direction for free in C/C++, I typically don't include the conversion explicitly in my code since I think it clutters things up and makes the code a bit harder to read. However, it doesn't hurt anything to put the conversion in there explicitly, so if you like it go ahead and leave it in. (Side Note: That 3rd argument would be automatically converted as well if you didn't pass in a size_t type).
The other way is different. Converting a void pointer to an object pointer requires explicit casting in C++.

댓글을 달려면 로그인하십시오.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by