Matlab Engine for C - Passing Arrays

3 views (last 30 days)
Arwel
Arwel on 19 Jul 2017
Edited: James Tursa on 20 Jul 2017
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

Answers (4)

Jan
Jan on 19 Jul 2017
Edited: Jan on 19 Jul 2017
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 on 19 Jul 2017
Edited: James Tursa on 19 Jul 2017
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 on 20 Jul 2017
Awesome, thanks guys! :)

Arwel
Arwel on 20 Jul 2017
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 Comment
James Tursa
James Tursa on 20 Jul 2017
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++.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!