Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
long int type in mexfunction

Subject: long int type in mexfunction

From: Richard Crozier

Date: 3 Feb, 2011 11:46:07

Message: 1 of 5

I am creating a gateway function to a C file which uses the long integer type. I cannot change the type in the C file.

The C file takes all of it's arguments as pointers (it is actually a conversion from a Fortran program created with the utility 'f2c').

I would like to ensure cross-platform compatibility of the routine. What is the best way to ensure that I am passing a type long int into my computation routine, taking account of the local processor architecture?

My gateway function is shown below (with some error checking code stripped out):

/* the gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
  double *W, *PRGOPT, *WS, *IP;
  int *MDW, *ME, *MA, *MG, *N;
  double *X, *RNORME, *RNORML;
  int *MODE;
  mwSize matm, matn;
  
  /* create a pointer to the input vector W */
  W = mxGetPr(prhs[0]);
  
  /* get the scalar input MDW */
  MDW = mxGetPr(prhs[1]);
  
    /* get the scalar input ME */
  ME = mxGetPr(prhs[2]);
  
    /* get the scalar input MA */
  MA = mxGetPr(prhs[3]);
  
    /* get the scalar input MG */
  MG = mxGetPr(prhs[4]);
  
    /* get the scalar input N */
  N = mxGetPr(prhs[5]);

    /* get the vector input PRGOPT */
  PRGOPT = mxGetPr(prhs[6]);
  
     /* get the vector input/output X */
  X = mxGetPr(prhs[7]);
  
    /* get the scalar input RNORME */
  RNORME = mxGetPr(prhs[8]);
  
    /* get the scalar input RNORML */
  RNORML = mxGetPr(prhs[9]);
  
    /* get the scalar input MODE */
  MODE = mxGetPr(prhs[10]);

    /* get the vector input WS */
  WS = mxGetPr(prhs[11]);
  
    /* get the vector input IP */
  IP = mxGetPr(prhs[12]);
  
  /* set the output pointer to the output matrix */
  //plhs[0] = mxCreateDoubleMatrix(mrows,ncols, mxREAL);
    /* set the output pointers to the output matrices */
  
  /* call the C subroutine */
  dlsei_(W, MDW, ME, MA, MG, N, PRGOPT, X, RNORME, RNORML, MODE, WS, IP);
  
  plhs[0] = mxDuplicateArray(prhs[7]);
  plhs[1] = mxDuplicateArray(prhs[8]);
  plhs[2] = mxDuplicateArray(prhs[9]);
  plhs[3] = mxDuplicateArray(prhs[10]);

}

Basically, how do I ensure that whatever I pass in from Matlab becomes a long int before being passed to dlsei_? Or alternatively, ensure that a long int is always 32 bits or something like this.

Thanks

Subject: long int type in mexfunction

From: James Tursa

Date: 3 Feb, 2011 16:12:06

Message: 2 of 5

"Richard Crozier" wrote in message <iie4hv$f3n$1@fred.mathworks.com>...
> I am creating a gateway function to a C file which uses the long integer type. I cannot change the type in the C file.
>
> The C file takes all of it's arguments as pointers (it is actually a conversion from a Fortran program created with the utility 'f2c').
>
> I would like to ensure cross-platform compatibility of the routine. What is the best way to ensure that I am passing a type long int into my computation routine, taking account of the local processor architecture?
>
> My gateway function is shown below (with some error checking code stripped out):
>
> /* the gateway function */
> void mexFunction( int nlhs, mxArray *plhs[],
> int nrhs, const mxArray *prhs[])
> {
> double *W, *PRGOPT, *WS, *IP;
> int *MDW, *ME, *MA, *MG, *N;
> double *X, *RNORME, *RNORML;
> int *MODE;
> mwSize matm, matn;
>
> /* create a pointer to the input vector W */
> W = mxGetPr(prhs[0]);
>
> /* get the scalar input MDW */
> MDW = mxGetPr(prhs[1]);
>
> /* get the scalar input ME */
> ME = mxGetPr(prhs[2]);
>
> /* get the scalar input MA */
> MA = mxGetPr(prhs[3]);
>
> /* get the scalar input MG */
> MG = mxGetPr(prhs[4]);
>
> /* get the scalar input N */
> N = mxGetPr(prhs[5]);
>
> /* get the vector input PRGOPT */
> PRGOPT = mxGetPr(prhs[6]);
>
> /* get the vector input/output X */
> X = mxGetPr(prhs[7]);
>
> /* get the scalar input RNORME */
> RNORME = mxGetPr(prhs[8]);
>
> /* get the scalar input RNORML */
> RNORML = mxGetPr(prhs[9]);
>
> /* get the scalar input MODE */
> MODE = mxGetPr(prhs[10]);
>
> /* get the vector input WS */
> WS = mxGetPr(prhs[11]);
>
> /* get the vector input IP */
> IP = mxGetPr(prhs[12]);
>
> /* set the output pointer to the output matrix */
> //plhs[0] = mxCreateDoubleMatrix(mrows,ncols, mxREAL);
> /* set the output pointers to the output matrices */
>
> /* call the C subroutine */
> dlsei_(W, MDW, ME, MA, MG, N, PRGOPT, X, RNORME, RNORML, MODE, WS, IP);
>
> plhs[0] = mxDuplicateArray(prhs[7]);
> plhs[1] = mxDuplicateArray(prhs[8]);
> plhs[2] = mxDuplicateArray(prhs[9]);
> plhs[3] = mxDuplicateArray(prhs[10]);
>
> }
>
> Basically, how do I ensure that whatever I pass in from Matlab becomes a long int before being passed to dlsei_? Or alternatively, ensure that a long int is always 32 bits or something like this.
>
> Thanks

The easiest thing to do is to check the sizeof(long int), see how many bits it is, and then use that type on the MATLAB side for all of your mex argument inputs (e.g., int32). You can always but a check in your mex routine to make sure that the inputs are the correct bitlength for the dlsei_ routine or throw an error.

The harder way is to convert all of your inputs inside the mex routine to the correct type, then pass *them* to the dlsei_ routine.

Q: If your dlsei_ routine is using long int, why are you using int above instead of long int?

You may have a problem with this line:

> /* get the vector input/output X */
> X = mxGetPr(prhs[7]);

as it appears you are using the prhs[7] variable as both input/output to the routine. So I am guessing that dlsei_ changes X inplace? Then you later copy the results to the output here:

> plhs[0] = mxDuplicateArray(prhs[7]);

This will change the input argument on the MATLAB side, which I don't think you want. You need to copy the input *first*, and then pass the copy to the dlsei_ routine.

Also, if all of your long int arguments are scalars, you are going about this the hard way. Just declare them as long int (not pointers) and then pass their addresses to dlsei_. e.g., instead of doing this for MDW:

> int *MDW;
     :
> /* get the scalar input MDW */
> MDW = mxGetPr(prhs[1]);
     :
> /* call the C subroutine */
> dlsei_(W, MDW, ME, MA, MG, N, PRGOPT, X, RNORME, RNORML, MODE, WS, IP);

it is easier to do this:

   long MDW;
     :
   /* get the scalar input MDW */
   MDW = mxGetScalar(prhs[1]);
     :
   /* call the C subroutine */
   dlsei_(W, &MDW, ME, MA, MG, N, PRGOPT, X, RNORME, RNORML, MODE, WS, IP);

And, of course, do the same thing for all of your other scalar long int inputs (not shown above).

 
James Tursa

Subject: long int type in mexfunction

From: Richard Crozier

Date: 4 Feb, 2011 12:38:04

Message: 3 of 5

"James Tursa" wrote in message <iiek4m$snu$1@fred.mathworks.com>...
> "Richard Crozier" wrote in message <iie4hv$f3n$1@fred.mathworks.com>...
> > I am creating a gateway function to a C file which uses the long integer type. I cannot...
snip
> > Thanks
>
> The easiest thing to do is to check the sizeof(long int), see how many bits it is, and then use that type on the MATLAB side for all of your mex argument inputs (e.g., int32). You can always but a check in your mex routine to make sure that the inputs are the correct bitlength for the dlsei_ routine or throw an error.
>
> The harder way is to convert all of your inputs inside the mex routine to the correct type, then pass *them* to the dlsei_ routine.
>
> Q: If your dlsei_ routine is using long int, why are you using int above instead of long int?
>
> You may have a problem with this line:
>
> > /* get the vector input/output X */
> > X = mxGetPr(prhs[7]);
>
> as it appears you are using the prhs[7] variable as both input/output to the routine. So I am guessing that dlsei_ changes X inplace? Then you later copy the results to the output here:
>
> > plhs[0] = mxDuplicateArray(prhs[7]);
>
> This will change the input argument on the MATLAB side, which I don't think you want. You need to copy the input *first*, and then pass the copy to the dlsei_ routine.
>
> Also, if all of your long int arguments are scalars, you are going about this the hard way. Just declare them as long int (not pointers) and then pass their addresses to dlsei_. e.g., instead of doing this for MDW:
>
> > int *MDW;
> :
> > /* get the scalar input MDW */
> > MDW = mxGetPr(prhs[1]);
> :
> > /* call the C subroutine */
> > dlsei_(W, MDW, ME, MA, MG, N, PRGOPT, X, RNORME, RNORML, MODE, WS, IP);
>
> it is easier to do this:
>
> long MDW;
> :
> /* get the scalar input MDW */
> MDW = mxGetScalar(prhs[1]);
> :
> /* call the C subroutine */
> dlsei_(W, &MDW, ME, MA, MG, N, PRGOPT, X, RNORME, RNORML, MODE, WS, IP);
>
> And, of course, do the same thing for all of your other scalar long int inputs (not shown above).
>
>
> James Tursa

Hi James, thanks for replying.

To answer you first question, that was just a mistake on my part, they should all be the long int type.

To reply to your more general comment about the variables being manipulated 'in place' this is indded the case, but this is dictated by the subroutine dlsei__. This routing was created from fortran source files via the conversion program f2c. In the original fortran program it is necesary to create arrays of the correct length for the output.

The variables W, PRGOPT, IP, MDW, ME, MA, MG, N ans IP are the real inputs

The variables X, RNORME, RNORML and MODE are the real outputs

The variables IP and WS are arrays used as workspace in dlsei__ and must be preallocated a certain minimum size based on the values on ME, MA, and N etc.

I'm not that hot on C programming and it is much simpler for me to preallocate all these variables in matlab to the correct sizes and pass these in.

I want also want to work on various machine architectures, including at least win32 and glnxa64 (64 bit linux). On my windowx XP machine a long int is 32 bits, on the linux machine a long int is 64 bits. I also have a 64 bit windows Vista machine I also want to work, I haven't tested the long int size on this yet. Matlab does not provide a command to get the size of a long int on the local machine, and this would probably be compiler specific anyway (correct me if I'm wrong though!).

So, based on this and your initial advice, I now have the following code

/* the gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
  double *W, *PRGOPT, *WS, *IP;
  long MDW, ME, MA, MG, N, MODE;
  double *X, *RNORME, *RNORML;
  double *MODEOUT;
  mwSize matm, matn;

/*
  printf("long int size: %zu", sizeof(long));
*/
    /* set the output pointers to the output matrices */
  plhs[0] = mxDuplicateArray(prhs[7]);
  plhs[1] = mxDuplicateArray(prhs[8]);
  plhs[2] = mxDuplicateArray(prhs[9]);
  
  /* create a pointer to the input vector W */
  W = mxGetPr(prhs[0]);
  
  /* get the scalar input MDW */
  MDW = (long) mxGetScalar(prhs[1]);
  
    /* get the scalar input ME */
  ME = (long) mxGetScalar(prhs[2]);
  
    /* get the scalar input MA */
  MA = (long) mxGetScalar(prhs[3]);
  
    /* get the scalar input MG */
  MG = (long) mxGetScalar(prhs[4]);
  
    /* get the scalar input N */
  N = (long) mxGetScalar(prhs[5]);

    /* get the vector input PRGOPT */
  PRGOPT = mxGetPr(prhs[6]);
  
    /* get the vector input/output X */
  X = mxGetPr(plhs[0]);
  
    /* get the scalar input RNORME */
  RNORME = mxGetPr(plhs[1]);
  
    /* get the scalar input RNORML */
  RNORML = mxGetPr(plhs[2]);
  
    /* get the scalar input MODE */
  MODE = (long) mxGetScalar(prhs[10]);

    /* get the vector input WS */
  WS = mxGetPr(prhs[11]);
  
    /* get the vector input IP */
  IP = mxGetPr(prhs[12]);

  plhs[3] = mxCreateDoubleMatrix(1, 1, mxREAL);

  MODEOUT = mxGetPr(plhs[3]);

  /* call the C subroutine */
  dlsei_(W, &MDW, &ME, &MA, &MG, &N, PRGOPT, X, RNORME, RNORML, &MODE, WS, IP);
  
  *MODEOUT = (double) MODE;
  
}

This does seem to work, but is there a better way to handle the X, RNORME and RNORML variables? RNORME and RNORML are always scalar doubles, X is an array of N doubles, i.e.they are created in the matlab calling function by:

rnorml = 0;
rnorme = 0;
x = zeros(N,1);

And will never have anything but zeros in them before being sent to dlsei__

Anyway, don't worry if you don't have time to answer this either, it's quite a long one! Thanks for your help so far anyway.

Subject: long int type in mexfunction

From: Richard Crozier

Date: 4 Feb, 2011 12:52:07

Message: 4 of 5

"Richard Crozier" wrote in message <iigrvc$im5$1@fred.mathworks.com>...
> "James Tursa" wrote in message <iiek4m$snu$1@fred.mathworks.com>...
> > "Richard Crozier" wrote in message <iie4hv$f3n$1@fred.mathworks.com>...

Oh, and please excuse the many typos in the last message. It was typed on a remote connection that renders by mouse cursor invisible, and doesn't allow the use of the arrow keys, or the DEL key!

Subject: long int type in mexfunction

From: James Tursa

Date: 4 Feb, 2011 19:16:02

Message: 5 of 5

"Richard Crozier" wrote in message <iigrvc$im5$1@fred.mathworks.com>...
>
> To reply to your more general comment about the variables being manipulated 'in place' this is indded the case, but this is dictated by the subroutine dlsei__. This routing was created from fortran source files via the conversion program f2c. In the original fortran program it is necesary to create arrays of the correct length for the output.
>
> The variables W, PRGOPT, IP, MDW, ME, MA, MG, N ans IP are the real inputs
>
> The variables X, RNORME, RNORML and MODE are the real outputs
>
> The variables IP and WS are arrays used as workspace in dlsei__ and must be preallocated a certain minimum size based on the values on ME, MA, and N etc.
>
> I'm not that hot on C programming and it is much simpler for me to preallocate all these variables in matlab to the correct sizes and pass these in.
>
> I want also want to work on various machine architectures, including at least win32 and glnxa64 (64 bit linux). On my windowx XP machine a long int is 32 bits, on the linux machine a long int is 64 bits. I also have a 64 bit windows Vista machine I also want to work, I haven't tested the long int size on this yet. Matlab does not provide a command to get the size of a long int on the local machine, and this would probably be compiler specific anyway (correct me if I'm wrong though!).
>
> So, based on this and your initial advice, I now have the following code
>
> /* the gateway function */
> void mexFunction( int nlhs, mxArray *plhs[],
> int nrhs, const mxArray *prhs[])
> {
> double *W, *PRGOPT, *WS, *IP;
> long MDW, ME, MA, MG, N, MODE;
> double *X, *RNORME, *RNORML;
> double *MODEOUT;
> mwSize matm, matn;
>
> /*
> printf("long int size: %zu", sizeof(long));
> */
> /* set the output pointers to the output matrices */
> plhs[0] = mxDuplicateArray(prhs[7]);
> plhs[1] = mxDuplicateArray(prhs[8]);
> plhs[2] = mxDuplicateArray(prhs[9]);
>
> /* create a pointer to the input vector W */
> W = mxGetPr(prhs[0]);
>
> /* get the scalar input MDW */
> MDW = (long) mxGetScalar(prhs[1]);
>
> /* get the scalar input ME */
> ME = (long) mxGetScalar(prhs[2]);
>
> /* get the scalar input MA */
> MA = (long) mxGetScalar(prhs[3]);
>
> /* get the scalar input MG */
> MG = (long) mxGetScalar(prhs[4]);
>
> /* get the scalar input N */
> N = (long) mxGetScalar(prhs[5]);
>
> /* get the vector input PRGOPT */
> PRGOPT = mxGetPr(prhs[6]);
>
> /* get the vector input/output X */
> X = mxGetPr(plhs[0]);
>
> /* get the scalar input RNORME */
> RNORME = mxGetPr(plhs[1]);
>
> /* get the scalar input RNORML */
> RNORML = mxGetPr(plhs[2]);
>
> /* get the scalar input MODE */
> MODE = (long) mxGetScalar(prhs[10]);
>
> /* get the vector input WS */
> WS = mxGetPr(prhs[11]);
>
> /* get the vector input IP */
> IP = mxGetPr(prhs[12]);
>
> plhs[3] = mxCreateDoubleMatrix(1, 1, mxREAL);
>
> MODEOUT = mxGetPr(plhs[3]);
>
> /* call the C subroutine */
> dlsei_(W, &MDW, &ME, &MA, &MG, &N, PRGOPT, X, RNORME, RNORML, &MODE, WS, IP);
>
> *MODEOUT = (double) MODE;
>
> }
>
> This does seem to work, but is there a better way to handle the X, RNORME and RNORML variables? RNORME and RNORML are always scalar doubles, X is an array of N doubles, i.e.they are created in the matlab calling function by:
>
> rnorml = 0;
> rnorme = 0;
> x = zeros(N,1);
>
> And will never have anything but zeros in them before being sent to dlsei__
>
> Anyway, don't worry if you don't have time to answer this either, it's quite a long one! Thanks for your help so far anyway.

This method is basically a waste of time and resources:

> */
> /* set the output pointers to the output matrices */
> plhs[0] = mxDuplicateArray(prhs[7]);
> plhs[1] = mxDuplicateArray(prhs[8]);
> plhs[2] = mxDuplicateArray(prhs[9]);

You apparently are creating the inputs to the mex routine for the sole purpose of duplicating them inside the mex routine to get the output variables to use. If N is small then no big deal ... you will never notice the waste. But if N is large then you may get some impacts. But aside from that, the whole interface would be confusing to another person quite frankly ... most people would expect m-files and mex files to create the outputs they need themselves rather than relying on correctly sized inputs for this. My advice on a better approach is to create the output arrays inside the mex routine itself. e.g., like this:

plhs[0] = mxCreateDoubleMatrix(N,1,mxREAL); // be sure you define N first
plhs[1] = mxCreateDoubleScalar(0.0);
plhs[2] = mxCreateDoubleScalar(0.0);
X = mxGetPr(plhs[0]);
RNORME = mxGetPr(plhs[1]);
RNORML = mxGetPr(plhs[2]);

And at the end, you could replace this code:

> plhs[3] = mxCreateDoubleMatrix(1, 1, mxREAL);
>
> MODEOUT = mxGetPr(plhs[3]);
>
> /* call the C subroutine */
> dlsei_(W, &MDW, &ME, &MA, &MG, &N, PRGOPT, X, RNORME, RNORML, &MODE, WS, IP);
>
> *MODEOUT = (double) MODE;

with this instead (a bit simpler for plhs[3]):

> /* call the C subroutine */
> dlsei_(W, &MDW, &ME, &MA, &MG, &N, PRGOPT, X, RNORME, RNORML, &MODE, WS, IP);
>
> plhs[3] = mxCreateDoubleScalar(MODE);


James Tursa

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us