change function pointer from library A in library B
My situation is the following:
I am writing a toolbox that generates two libraries. The first (A) has all the functions and data-types and can be used in a pure C++ application; the second (B) is an interface to MATLAB. A pure C++ program would be compiled with
g++ $(FLAGS) C.cpp $(MOREFLAGS) -lA
while a MATLAB program would be compiled with B linked after A, i.e.
mex $(FLAGS) C.cpp $(MOREFLAGS) -lA -lB
Now, I would like use a function pointer (myexit
) to call std::exit()
for pure C++ applications and mex_exit()
(which calls mexErrMsgTxt()
) for MATLAB applications. Following a tutorial on function pointers, I've written something like the snippets below (everything is actually within a namespace, but I have suppressed this for brevity).
//A.hpp
#ifndef __A
#define __A
extern void (*myexit)(int);
...
#ifdef mex_h /* defined in mex.h */
#include "B.hpp"
#endif /* mex_h */
#endif /* __A */
//A.cpp
#include "A.hpp"
void (*myexit)(int) = &std::exit;
//B.hpp
#ifndef __B
#define __B
#include <mex.h>
#include "A.hpp"
...
void mex_exit(int);
#endif /* __B */
//B.cpp
#include <mex.h>
#include "A.hpp"
void mex_exit(int err) {mexPrintf("Er开发者_StackOverflowror code %d\n",err); mexErrMsgTxt("...");}
//void (*myexit)(int) = &mex_exit; // <- I want a line like this to override the line in A.cpp
What I have above seems to work for pure C++ code and I find that I can get the right behaviour for MATLAB code if I include the line myexit = &mex_exit;
in C.cpp, however, I want this behaviour simply from having #include <mex.h>
and #include "A.hpp"
in C.cpp and linking to B (i.e. it shouldn't be the user's responsibility to include this line).
Is this possible? If so, then how?
In library B, add a static constructor to set myexit
:
// Consider putting this into a namespace
extern void (*myexit)(int);
// anonymous namespace to avoid name collisions
namespace {
class StaticInit {
StaticInit() {
myexit = mex_exit;
}
} static_init_obj;
}
Then link library B to depend on library A:
gcc -o libB.so -shared -lA -lmatlab b.o
Because libB depends on libA, libA static constructors will be invoked before libB static constructors, so ordering isn't a problem. The StaticInit
constructor will be invoked during program startup (before main()
), and set myexit
for you.
You could apply the GCC constructor
function attribute to a function in B.cpp
, which overwrites the value of myexit
.
Not portable, of course.
I'm not sure that it's possible to do what you're asking (portably, that is). Perhaps the best you can do is provide an init
function in B that sets everything up for "Matlab mode", including changing the myexit
function pointer. That way, the user is not aware of implementation details. The advantage with this approach is if later you need to add more initialization code, you can add it inside the init
function without breaking the client's code.
I think it's a bad idea for a function pointer to be part of a library's API. You should provide a myexit
function that invokes the function pointer on behalf of the user:
void myexit(int err) {myexit_fn_ptr(err);}
While you're at it, provide a cleanup function as part of your library API. This function is the counterpart to init
and must be called by the client before the program exits so that the library may perform cleanup. Even if you currently don't have cleanup work to do, add an empty cleanup function to your API anyway so that you have a placeholder for the future.
精彩评论