изменить указатель на функцию из библиотеки A в библиотеке B - PullRequest
3 голосов
/ 26 июля 2011

Моя ситуация следующая:

Я пишу набор инструментов, который генерирует две библиотеки.Первый (A) имеет все функции и типы данных и может использоваться в чистом приложении C ++;второй (B) - это интерфейс к MATLAB.Программа на чистом C ++ будет скомпилирована с

g++ $(FLAGS) C.cpp $(MOREFLAGS) -lA

, тогда как программа MATLAB будет скомпилирована с B, связанным после A, то есть

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

Теперь я хотел бы использовать указатель на функцию (myexit) для вызова std::exit() для приложений на чистом C ++ и mex_exit() (который вызывает mexErrMsgTxt()) для приложений MATLAB.Следуя руководству по указателям на функции, я написал что-то вроде приведенных ниже фрагментов (на самом деле все находится в пространстве имен, но для краткости я это исключил).

//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

То, что у меня есть выше, похоже, работает длячистого кода на C ++, и я обнаружил, что могу получить правильное поведение для кода MATLAB, если я включу строку myexit = &mex_exit; в C.cpp, однако я хочу, чтобы это поведение было просто из-за наличия #include <mex.h> и #include "A.hpp" в C.cpp иссылка на B (т. е. пользователь не должен включать эту строку).

Возможно ли это?Если так, то как?

Ответы [ 3 ]

3 голосов
/ 26 июля 2011

В библиотеке 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.

1 голос
/ 26 июля 2011

Вы можете применить атрибут функции GCC constructor к функции в B.cpp, которая перезаписывает значение myexit.

Конечно, не переносимо.

0 голосов
/ 26 июля 2011

Я не уверен, что возможно сделать то, что вы просите (то есть, что угодно).Возможно, лучшее, что вы можете сделать, это предоставить функцию init в B, которая настраивает все для «режима Matlab», включая изменение указателя функции myexit.Таким образом, пользователь не знает деталей реализации.Преимущество этого подхода в том, что если позже вам потребуется добавить больше кода инициализации, вы можете добавить его в функцию init, не нарушая код клиента.

Я думаю, что указатель на функцию плохой идеейчасть API библиотеки.Вы должны предоставить функцию myexit, которая вызывает указатель на функцию от имени пользователя:

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

Пока вы работаете с ней, предоставьте функцию очистки как часть API вашей библиотеки.Эта функция является аналогом init и должна вызываться клиентом до выхода из программы, чтобы библиотека могла выполнить очистку.Даже если в настоящее время у вас нет работы по очистке, в любом случае добавьте пустую функцию очистки в свой API, чтобы у вас был заполнитель на будущее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...