我的情况如下:
我正在编写一个生成两个库的工具箱。第一个(A)具有所有函数和数据类型,可以在纯C ++应用程序中使用;第二个(B)是MATLAB的接口。 一个纯C ++程序将用
编译g++ $(FLAGS) C.cpp $(MOREFLAGS) -lA
而MATLAB程序将在A之后用B链接编译,即
mex $(FLAGS) C.cpp $(MOREFLAGS) -lA -lB
现在,我想使用函数指针(myexit
)为纯C ++应用程序调用{{1}},为MATLAB应用程序调用{{1}}(调用std::exit()
)。在关于函数指针的教程之后,我写了类似下面的片段(一切都在命名空间内,但为了简洁起见我已经将其抑制了)。
mex_exit()
我上面的内容似乎适用于纯C ++代码,我发现如果我在C.cpp中包含行mexErrMsgTxt()
,我可以获得MATLAB代码的正确行为,但是,我希望这个行为只是来自在C.cpp中有//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("Error code %d\n",err); mexErrMsgTxt("...");}
//void (*myexit)(int) = &mex_exit; // <- I want a line like this to override the line in A.cpp
和myexit = &mex_exit;
并链接到B(即用户不应该包含此行)。
这可能吗?如果是这样,那怎么样?
答案 0 :(得分:3)
在库B中,添加一个静态构造函数来设置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;
}
然后链接库B以依赖库A:
gcc -o libB.so -shared -lA -lmatlab b.o
因为libB依赖于libA,所以在libB静态构造函数之前将调用libA静态构造函数,因此排序不是问题。 StaticInit
构造函数将在程序启动期间(main()
之前)调用,并为您设置myexit
。
答案 1 :(得分:1)
您可以将GCC constructor
function attribute应用于B.cpp
中的函数,该函数会覆盖myexit
的值。
当然不便携。
答案 2 :(得分:0)
我不确定你可以做什么(可移植,就是这样)。也许您可以做的最好的事情是在B中提供init
函数,为“Matlab模式”设置所有内容,包括更改myexit
函数指针。这样,用户就不知道实现细节。这种方法的优点是,如果以后需要添加更多初始化代码,可以将其添加到init
函数中,而不会破坏客户端的代码。
我认为将函数指针作为库API的一部分是个坏主意。您应该提供一个myexit
函数,代表用户调用函数指针:
void myexit(int err) {myexit_fn_ptr(err);}
当您使用它时,请提供清理功能作为库API的一部分。此函数与init
的对应函数必须在程序退出之前由客户端调用,以便库可以执行清理。即使您目前没有要进行清理工作,也要在API中添加一个空的清理功能,以便您拥有未来的占位符。