从库A更改函数指针到库B

change function pointer from library A in library B

本文关键字:指针 函数 从库      更新时间:2023-10-16

我的情况如下:

我正在编写一个生成两个库的工具箱。第一个(A)具有所有的函数和数据类型,可以在纯c++应用程序中使用;第二个(B)是MATLAB的接口。用

编译一个纯c++程序
g++ $(FLAGS) C.cpp $(MOREFLAGS) -lA

,而MATLAB程序编译时会将B链接在a之后,即

mex $(FLAGS) C.cpp $(MOREFLAGS) -lA -lB

现在,我想使用函数指针(myexit)来调用纯c++应用程序的std::exit()和MATLAB应用程序的mex_exit()(调用mexErrMsgTxt())。在关于函数指针的教程之后,我编写了类似下面的代码片段(实际上所有内容都在一个名称空间中,但为了简洁起见,我省略了这些内容)。

//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 %dn",err); mexErrMsgTxt("...");}
//void (*myexit)(int) = &mex_exit; // <- I want a line like this to override the line in A.cpp

我上面的内容似乎适用于纯c++代码,我发现如果我在C.cpp中包含myexit = &mex_exit;行,我可以获得MATLAB代码的正确行为,但是,我想要这种行为仅仅是在C.cpp中具有#include <mex.h>#include "A.hpp"并链接到B(即不应该是用户的责任包括这一行)。

这可能吗?如果是,那又是怎么回事?

在库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, libA静态构造函数将在libB静态构造函数之前被调用,所以排序不是问题。StaticInit构造函数将在程序启动期间(在main()之前)被调用,并为您设置myexit

您可以将GCC constructor function属性应用于B.cpp中的函数,该函数将覆盖myexit的值。

当然不能移植

我不确定是否有可能做到您所要求的(即可移植)。也许你能做的最好的是在B中提供一个init函数,为"Matlab模式"设置一切,包括改变myexit函数指针。这样,用户就不知道实现细节。这种方法的优点是,如果以后您需要添加更多的初始化代码,您可以将其添加到init函数中,而不会破坏客户端代码。

我认为函数指针作为库API的一部分是一个坏主意。您应该提供一个myexit函数,代表用户调用函数指针:

void myexit(int err) {myexit_fn_ptr(err);}

同时,提供一个清理函数作为库API的一部分。此函数与init对应,必须在程序退出之前由客户端调用,以便库可以执行清理。即使您目前没有清理工作要做,也可以向API添加一个空的清理函数,以便将来有一个占位符。