JustinBlaber
JustinBlaber

Reputation: 4650

Passing integer types to a mex function

I'm currently using a mex function where integers are sent as a parameter by first converting it to int type with:

a = int32(10);
foo(a);

Where foo receives/checks a by using:

void get_integer_scalar(int &scalar,const mxArray *mat_buf) {
    // Check input
    if (mxIsClass(mat_buf,"int32")) {
        if (mxGetN(mat_buf) == 1 &&  mxGetM(mat_buf) == 1) {
            // At this point, input is correct
            scalar = *((int *)mxGetData(mat_buf));
        } else {
            mexErrMsgTxt("Integer scalar is not of size == [1 1].\n");
        }
    } else {
        mexErrMsgTxt("Integer scalar is not int32.\n");
    }
}

Now, it just sort of dawned upon me that the int type is machine dependent, so the line scalar = *((int *)mxGetData(mat_buf)); might be unsafe (or is it? I'm trying to not make assumptions about how int32() works in matlab). Is there a safe way to pass a standard int type to a mex file or should I be using a 32 bit int type like int32_t?

Upvotes: 2

Views: 5638

Answers (1)

chappjc
chappjc

Reputation: 30579

Use mxGetScalar, which returns a double value, no matter what the input type, which you can cast without worry.

double mxGetScalar(const mxArray *pm); // the type of data in pm doesn't matter

In C, mxGetScalar returns a double. If real elements in the mxArray are of a type other than double, mxGetScalar automatically converts the scalar value into a double. To preserve the original data representation of the scalar, cast the return value to the desired data type.

Just check the number of elements, and you don't even need a type check (but I would use mxIsInt32 for that, if needed):

#include <mex.h>

void get_integer_scalar(int &scalar,const mxArray *mat_buf) {
    // Check input
    if (!mxIsInt32(mat_buf))
        mexPrintf("Integer scalar is not int32, but that's OK.\n");

    if (mxGetNumberOfElements(mat_buf) == 1) {
        scalar = mxGetScalar(mat_buf);
    } else {
        mexErrMsgTxt("Integer scalar is not of size == [1 1].\n");
    }
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    int val;
    if (nrhs>0)
    {
        get_integer_scalar(val,prhs[0]); // type of prhs[0] does not matter
        mexPrintf("%d\n",val);
    }
}

To answer your question, MATLAB's int32 is obviously not machine dependent, but as you pointed out there are no guarantees that C++ int will be 32-bit. I think mxGetScalar addresses this for scalars, but for arrays (when you need a pointer safely casted) I think you are right that you can use <stdint.h> or <cstdint>, which set int8_t, int16_t, int32_t, int64_t, etc. Visual Studio does typedef int int32_t;.

MATLAB also has a header for this purpose: tmwtypes.h. It sets the following fixed-width types:

/*=======================================================================*
 * Fixed width word size data types:                                     *
 *   int8_T, int16_T, int32_T     - signed 8, 16, or 32 bit integers     *
 *   uint8_T, uint16_T, uint32_T  - unsigned 8, 16, or 32 bit integers   *
 *   real32_T, real64_T           - 32 and 64 bit floating point numbers *
 *=======================================================================*/

And here's the relevant piece for int32_T:

#ifndef INT32_T
# if   TMW_BITS_PER_INT   == 32
#  define  INT32_T int
# elif TMW_BITS_PER_LONG  == 32
#  define  INT32_T long
# elif TMW_BITS_PER_SCHAR == 32
#  define  INT32_T signed char
# elif TMW_BITS_PER_SHRT  == 32
#  define  INT32_T short
# endif
#endif
#ifdef INT32_T
 typedef INT32_T int32_T;
#endif

It gets TMW_BITS_PER_INT earlier in the header by comparing INT_MAX with various hexadecimal literals, and 0x7FFFFFFFL wins out. Basically, you can use int32_T, as described in the docs for mxClassID, if you are including tmwtypes.h.

However, I doubt MATLAB supports any tool set that uses anything but a 32-bit unsigned integer for int.

Upvotes: 4

Related Questions