Why do functions that call by reference not work when they are linked from other source files in a mex wrapper?

2 views (last 30 days)
Derek
Derek on 14 Jul 2016
Edited: James Tursa on 14 Jul 2016
I have written two functions 'refFunc' and 'valFunc' in two seperate .c files with header files. I attempted to compile them along with a mex wrapper function 'mainmex' and link them together to form a mex executable. The function 'refFunc' takes an 'int' and returns that integer multiplied by 2. The function 'valFunc' does the same thing, only it calls by reference instead of calling by value and it doesn't return anything. 'valFunc' executes just fine, but 'refFunc' causes an access violation.
As a sanity check, I repeated the same steps with a "vanilla" c wrapper 'mainc'. The function executed just fine without any problems. Is there some quirk in Matlab that is causing this? Or am I doing something wrong?
Here is the code for mainmex.c
#include "mex.h"
#include "valFunc.h"
#include "refFunc.h"
#include <stdio.h>
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
printf("executing valFunc, answer is %i\n", valFunc((int)5));
int *b;
*b = 0;
printf("executing valFunc, ...");
refFunc((int)5, b);
printf("b is %i\n", *b);
}
And for refFunc.c
#include "refFunc.h" /*Doesn't seem to make a difference whether or not I
include the header file*/
void refFunc(int a, int *b)
{
*b = 2 * a;
}
And for valFunc.c
#include "valFunc.h" /*Doesn't seem to make a difference whether or not I
include the header file*/
int valFunc(int a)
{
int b = a * 2;
return b;
}
And for refFunc.h
void refFunc(int a, int *b);
And for valFunc.h
int valFunc(int a);
And for mainc.c
#include "valFunc.h"
#include "refFunc.h"
#include <stdio.h>
void main()
{
printf("executing valFunc, answer is %i\n", valFunc((int)5));
int *b;
*b = 0;
printf("executing valFunc, ...");
refFunc((int)5, b);
printf("b is %i\n", *b);
}
And finally, the command I am using to compile and run the mex and the output I got
When I switched to bash, I did the following and got the following:
$ gcc mainc.c valFunc.obj refFunc.obj -fno-use-linker-plugin
$ ./a.exe
executing valFunc, answer is 10
executing valFunc, ...b is 10
  1 Comment
Derek
Derek on 14 Jul 2016
Answer was provided on Stack Overflow. Apparently the code for mainmex.c passes a null pointer to refFunc. I should've just done the following instead.
#include "valFunc.h"
#include "refFunc.h"
#include <stdio.h>
void main()
{
printf("executing valFunc, answer is %i\n", valFunc((int)5));
int *b;
*b = 0;
printf("executing valFunc, ...");
refFunc((int)5, b);
printf("b is %i\n", *b);
}
That way, the pointer would actually be pointing to something.
Credit to Stack Overflow user John Bollinger for the answer.

Sign in to comment.

Answers (1)

James Tursa
James Tursa on 14 Jul 2016
Edited: James Tursa on 14 Jul 2016
No. You still don't have it correct. I don't know what the discussion on Stack Overflow was, but the problem has nothing to do with passing a NULL pointer to the function. It has to do with passing an uninitialized pointer. You actually have two related problems. For starters, these two lines:
int *b;
*b = 0;
Variable b is a pointer. You cannot legally dereference it until you set it to point to a valid memory address (e.g. to another variable or to allocated memory). So this line is invalid:
*b = 0
It dereferences an uninitialized pointer, and could either poke a 0 into some random memory location or crash the program with an invalid memory access error. Both bad. This line does not set b to a NULL pointer! It dereferences the address contained in b (currently garbage) and pokes a 0 into that memory location. Bad. After this line executes, b is still uninitialized and contains garbage. Then when you get to this line:
refFunc((int)5, b); // <-- b is uninitialized
You are passing in the value of b, but b was never assigned a value. It is uninitialized and contains garbage. So that is your second problem, since refFunc dereferences b and inside the function. I.e., this line inside refFunc:
*b = 2 * a;
Has the same problem discussed earlier ... it dereferences an uninitialized pointer and pokes a value into a garbage memory location. You will either get bad results or crash the program.
If you really wanted to use a pointer for this line, you would need to do something like the following:
int *b;
b = (int *) mxMalloc( 1 * sizeof(*b) ); // <-- Set b to a valid value
*b = 0; // <-- Not really necessary since refFunc will set this value anyway
:
mxFree(b);
But using a pointer for this is overkill. Just pass the address of an int to your function. E.g., here is what your standalone program should look like:
#include "valFunc.h"
#include "refFunc.h"
#include <stdio.h>
void main()
{
int b; // <-- make b an int, not a pointer_to_int
printf("executing valFunc, answer is %i\n", valFunc(5));
printf("executing refFunc, ...");
refFunc(5, &b); // <-- pass the address of b into the function
printf("b is %i\n", b); // <-- simply print out b
}
And similarly, your mex code should look like this:
#include "mex.h"
#include "valFunc.h"
#include "refFunc.h"
#include <stdio.h>
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
int b;
mexPrintf("executing valFunc, answer is %i\n", valFunc(5));
mexPrintf("executing refFunc, ...");
refFunc(5, &b);
mexPrintf("b is %i\n", b);
}
The fact that you ever got results from your current code was just pure luck ... BAD luck in my opinion. It would have been better had the program crashed on you so you knew you still had a programming problem to fix.

Products

Community Treasure Hunt

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

Start Hunting!

Translated by