Fortran MEX using Cell arrays - crashing Matlab..
1 view (last 30 days)
Show older comments
Hi, I am trying to learn how to use cell arrays in Mex functions. I've written a simple test function below, which should take a cell array of doubles, then simply square each element. So from Matlab if...
A = {[1 2 3] ; [1 2 3]}
.. then B = mexGateway(A)
should give B = {[1 4 9];[1 4 9]}.
But, it just crashes Matlab. From the debugger, the crash happens when it tries to call compute. What have I missed here, and how should this be changed to make it work? Cheers, Arwel
#include "fintrf.h"
C-------------------------------------------------------------------------------
C Test program that inputs cell array of double arrays, squares each element
C then outputs the results in a new cell array
C--------------------------------------------------------------------------------
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C Declarations
implicit none
C Mex function arguments
mwPointer plhs(*), prhs(*), dat
integer nlhs, nrhs
C Function Declarations
mwPointer mxCreateCellMatrix
mwPointer mxGetCell
mwPointer mxSetCell
mwPointer mxGetData
mwPointer mxGetPr
mwPointer mxGetNumberOfElements
mwSize i, m
C Pointers Arrays and vars
mwPointer numberOfCells
mwPointer outputArray
mwPointer inputArray
mwPointer thisCell
mwPointer calcOutpArray
mwPointer size
C input checking to be added..
C Get the size of the input array..
inputArray = prhs(1)
numberOfCells = mxGetNumberOfElements(inputArray)
C Output cell array will have the same dimensions
outputArray = mxCreateCellMatrix(numberOfCells,1)
c Loop over all the elements in the input array and call comp...
do 10 i=1,numberOfCells
thisCell = mxGetCell(inputArray,i)
size = mxGetNumberOfElements(thisCell)
call compute(%VAL(calcOutpArray),%VAL(thisCell),%VAL(size))
call mxSetCell(outputArray,i,calcOutpArray)
10 continue
plhs(1) = outputArray
return
end
C -----------------------------------------------------------
subroutine compute(outArray,inArray,l)
real*8 outArray(l,1), inArray(l,1)
real*8 n
do 20 n=1,l
outArray(n,1) = inArray(n,1)*inArray(n,1)
20 continue
return
end
0 Comments
Answers (4)
dpb
on 20 Jul 2016
Subroutine compute is Fortran, don't need (and can't use) %VAL on the arguments; they'll be handled just like any other Fortran argument.
call compute(calcOutpArray,thisCell,size)
0 Comments
James Tursa
on 20 Jul 2016
Edited: James Tursa
on 21 Jul 2016
You are not creating any output cells, so you are writing to garbage address locations which will eventually result in a MATLAB crash. I.e., in this line
call compute(%VAL(calcOutpArray),%VAL(thisCell),%VAL(size))
calcOutpArray hasn't been set to anything prior to this call. Plus you aren't even passing the correct thing anyway as dpb has pointed out. This section of code should look something like this:
mwSize m, n
integer*4 :: ComplexFlag = 0
mwPointer pr_out, pr_in
:
m = numberOfCells
n = 1
outputArray = mxCreateCellMatrix(m,n) ! <-- Always pass variables for sizes, not literal constants
:
do i=1,numberOfCells
thisCell = mxGetCell(inputArray,i) ! <-- This is an (mxArray *)
m = mxGetNumberOfElements(thisCell)
n = 1
calcOutpArray = mxCreateDoubleMatrix(m,n,ComplexFlag) ! <-- This is an (mxArray *)
pr_in = mxGetPr(thisCell) ! <-- This is a (double *)
pr_out = mxGetPr(calcOutpArray) ! <-- This is a (double *)
call compute(%VAL(pr_out),%VAL(pr_in),m) ! <-- Pass value of (double *) to compute
call mxSetCell(outputArray,i,calcOutpArray)
enddo
:
:
subroutine compute(outArray,inArray,l)
mwSize l
real*8 outArray(l,1), inArray(l,1)
mwSize n
The %VAL( ) constructs work in the above code because the subroutine compute has an implicit interface. If it had an explicit interface you would need to do something else.
And, Fortran is an array based language, like MATLAB. So these lines of code:
do 20 n=1,l
outArray(n,1) = inArray(n,1)*inArray(n,1)
20 continue
Can be reduced to this one statement, since * is element-wise multiply in Fortran:
outArray = inArray*inArray
CAUTION: This all assumes that the input argument is EXACTLY as expected. If not, you will probably get a crash. E.g., if one of the cell elements of the input variable is not set, it will physically contain a NULL address (0 in Fortran). So for that iteration you would have thisCell = 0, and subsequent lines that use thisCell will probably crash MATLAB. To make your code robust against this, you need to check that thisCell is not 0, and if you pass that then check to see that it is double class and not sparse etc etc. So you need to put in lots of checks like this to make sure your code doesn't crash MATLAB for unexpected inputs.
0 Comments
Arwel
on 20 Jul 2016
Edited: Arwel
on 20 Jul 2016
1 Comment
James Tursa
on 20 Jul 2016
You already have that correct:
plhs(1) = outputArray
See Also
Categories
Find more on Performance and Memory in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!