Byte ordering in calls from C/C++ to a Matlab-compiled DLL

2 views (last 30 days)
I am having a strange issue with passing information to and from a compiled MATLAB DLL from C/C++.
First, here is my function:
function y = foo(x)
a=0.5;
y=x.*a;
And here is how I compile it using Microsoft VS 9.0:
mcc -B csharedlib:foolib foo.m -C
And here is my C++ pseudo-code:
In header
mxArray *x_ptr, *y_ptr;
In constructor
mclInitializeApplication(NULL,0);
foolibInitialize();
In main
// note: myBuffer is a float* of length numSamples
x_ptr = mxCreateDoubleMatrix(numSamples, 1, mxREAL);
y_ptr = mxCreateDoubleMatrix(numSamples, 1, mxREAL);
memcpy(mxGetPr(x_ptr), (double*)myBuffer, numSamples*sizeof(double));
mlfFoo(1, &y_ptr, x_ptr);
memcpy(myBuffer, (float*)mxGetPr(y_ptr), numSamples*sizeof(float));
My deconstructor
foolibTerminate();
mxDestroyArray(x_ptr); x_ptr=NULL;
mxDestroy(y_ptr); y_ptr = NULL;
mclTerminateApplication();
But here is the weird part - if a (in foo.m) is 1/2 or 1/4 or 1/8, etc. then while it doesn't sound like gain is really being applied (in fact it sounds slightly distorted), at least it is passing through the input. However, if I use ANY other gain values, e.g. 0.51 instead of 0.50, the output is complete and utter garbage.
In researching this problem, I realized that the fractions listed above only alter the exponent of a float, and doing an odd fraction such as 0.51 also changes the mantissa.
So my thoughts are that there is some sort of endianness or byte-ordering problem going on?!? Does anyone have any thoughts on this?!?!?

Accepted Answer

James Tursa
James Tursa on 20 Jul 2011
I don't think you understood what Walter was getting at. These lines will not work if myBuffer is supposed to contain float data:
memcpy(mxGetPr(x_ptr), (double*)myBuffer, numSamples*sizeof(double));
memcpy(myBuffer, (float*)mxGetPr(y_ptr), numSamples*sizeof(float));
Simply casting the result of mxGetPr, a double * , to a float * , does not change the fact that the underlying data that it is pointing to is still double. And vice-versa for the double * cast you have on myBuffer. You will need to physically write a for-loop and do the conversion from single-to-double (or the reverse) manually one element at a time. You cannot use memcpy for this.
As a side note, it is pointless to put any cast at all for the 2nd argument to memcpy since the compiler will immediately turn around and cast it to a void * per the prototype. (You did include the prototype, right?).
  2 Comments
Oygo
Oygo on 21 Jul 2011
Thank you so much, James!
After taking your suggestion and Walter's suggestion, I was able to fix my code. For posterity's sake, here is my new implementation:
y = new double[numSamples];
x = new double[numSamples];
x_ptr = mxCreateDoubleMatrix(numSamples, 1, mxREAL);
y_ptr = mxCreateDoubleMatrix(numSamples, 1, mxREAL);
for (int ii=0; ii<numSamples; ii++)
x[ii] = (double)myBuffer[ii]; // cast float to double
memcpy(mxGetPr(x_ptr), x, numSamples*sizeof(double));
mlfFoo(1, &y_ptr, x_ptr);
y = mxGetPr(y_ptr);
for (int ii=0; ii<numSamples; ii++)
myBuffer[ii] = (float)y[ii]; // cast double to float
delete [] y;
delete [] x;
Maybe there is a 'prettier' way to do this, but hey, it works!
James Tursa
James Tursa on 21 Jul 2011
Your code does a conversion *and* a separate copy. Also it looks like you have a bug with your y (first it is allocated as a new double array, then you wipe that value out and set it to the result of a mxGetPr(y_ptr) call, then you call delete [] on it). To fix the bug and combine all this into one step and avoid the extra copy you can do this:
double *y;
double *x;
x_ptr = mxCreateDoubleMatrix(numSamples, 1, mxREAL);
y_ptr = mxCreateDoubleMatrix(numSamples, 1, mxREAL);
x = mxGetPr(x_ptr);
for (int ii=0; ii<numSamples; ii++)
x[ii] = (double)myBuffer[ii]; // cast float to double
mlfFoo(1, &y_ptr, x_ptr);
y = mxGetPr(y_ptr);
for (int ii=0; ii<numSamples; ii++)
myBuffer[ii] = (float)y[ii]; // cast double to float

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 20 Jul 2011
In some parts of your code you are treating myBuffer as being an array of double, and in other parts you are treating it as being an array of float. That seems to be asking for trouble. I don't know why you are thinking that your foo function will be returning a float when it does not use single() to force the computation result to single precision.
  1 Comment
Oygo
Oygo on 20 Jul 2011
Yes, the float<->double conversions are an annoyance. 'myBuffer' is really shorthand for an object that I have access to. That object is of *float-type, and MATLAB DLL returns *double-type, so the back-and-forth is necessary, unfortunately. I will try forcing foo to single() precision.

Sign in to comment.

Categories

Find more on MATLAB Compiler in Help Center and File Exchange

Products

Community Treasure Hunt

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

Start Hunting!