Matlab Engine for C - Passing Arrays

2 次查看(过去 30 天)
Arwel
Arwel 2017-7-19
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
编辑: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++.

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Call MATLAB from C 的更多信息

Community Treasure Hunt

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

Start Hunting!

Translated by