将 C++ 函数指针转换为 c 函数指针
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19808054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert C++ function pointer to c function pointer
提问by RRR
I am developing a C++ application using a C library. I have to send a pointer to function to the C library.
我正在使用 C 库开发 C++ 应用程序。我必须向 C 库发送一个指向函数的指针。
This is my class:
这是我的课:
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
Ui::MainWindow *ui;
void f(int*);
private slots:
void on_btn_clicked();
};
This is my on_btn_clicked function:
这是我的 on_btn_clicked 函数:
void MainWindow::on_btn_clicked()
{
void (MainWindow::* ptfptr) (int*) = &MainWindow::f;
c_library_function(static_cast<void()(int*)>(ptfptr), NULL);
}
The C function should get a pointer to a such function : void f(int*). But the code above doesn't work, I cannot succeed to convert my f member function to the desired pointer.
C 函数应该得到一个指向这样的函数的指针:void f(int*)。但是上面的代码不起作用,我无法成功将我的 f 成员函数转换为所需的指针。
Can anybody please help?
有人可以帮忙吗?
采纳答案by Ferenc Deak
If I recall it correctly, Only static methods of a class can be accessed via "normal" C pointer to function syntax. So try to make it static. The pointer to a method of a class needs extra information, such as the "object" (this) which has no meaning for a pure C method.
如果我没记错的话,只能通过指向函数语法的“普通”C 指针访问类的静态方法。所以尽量让它静态。指向类方法的指针需要额外的信息,例如“对象”(this)对于纯 C 方法没有意义。
The FAQ shown herehas good explanation and a possible (ugly) solution for your problem.
此处显示的常见问题解答对您的问题有很好的解释和可能的(丑陋的)解决方案。
回答by Tristan Brindle
You can't pass a non-static member function pointer as an ordinary function pointer. They're not the same thing, and probably not even the same size.
您不能将非静态成员函数指针作为普通函数指针传递。它们不是一回事,甚至可能大小也不一样。
You can however (usually) pass a pointer to a staticmember function through C. Usually when registering a callback in a C API, you also get to pass a "user data" pointer which gets passed back to your registered function. So you can do something like:
但是,您可以(通常)通过 C传递一个指向静态成员函数的指针。通常在 C API 中注册回调时,您还可以传递一个“用户数据”指针,该指针将被传递回您注册的函数。因此,您可以执行以下操作:
class MyClass
{
void non_static_func(/* args */);
public:
static void static_func(MyClass *ptr, /* other args */) {
ptr->non_static_func(/* other args */);
}
};
Then register your callback as
然后将您的回调注册为
c_library_function(MyClass::static_func, this);
i.e. pass the instance pointer to the static method, and use that as a forwarding function.
即将实例指针传递给静态方法,并将其用作转发函数。
Strictly speaking for total portability you need to use a free function declared extern "C"
rather than a static member to do your forwarding (declared as a friend
if necessary), but practically speaking I've never had any problems using this method to interface C++ code with GObject code, which is C callback-heavy.
严格来说,为了完全可移植性,您需要使用声明的自由函数extern "C"
而不是静态成员来进行转发(friend
如有必要,声明为 a ),但实际上,使用此方法将 C++ 代码与 GObject 代码连接起来,我从未遇到任何问题,这是 C 回调重。
回答by Snps
You can't pass a function pointer to a non-static member function. What you can do is to create a static or global function that makes the call with an instance parameter.
您不能将函数指针传递给非静态成员函数。您可以做的是创建一个静态或全局函数,使用实例参数进行调用。
Here's an example I find useful which uses a helper class with two members: a function wrapper and a callback function that calls the wrapper.
这是一个我觉得有用的例子,它使用了一个具有两个成员的帮助类:一个函数包装器和一个调用包装器的回调函数。
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
static Ret callback(Args... args) { return func(args...); }
static std::function<Ret(Params...)> func;
};
// Initialize the static member.
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
Using this you can store any callable, even non-static member functions (using std::bind
) and convert to a c-pointer using the Callback::callback
function. E.g:
使用它,您可以存储任何可调用的,甚至是非静态成员函数(使用std::bind
)并使用该Callback::callback
函数转换为 c 指针。例如:
struct Foo {
void print(int* x) { // Some member function.
std::cout << *x << std::endl;
}
};
int main() {
Foo foo; // Create instance of Foo.
// Store member function and the instance using std::bind.
Callback<void(int*)>::func = std::bind(&Foo::print, foo, std::placeholders::_1);
// Convert callback-function to c-pointer.
void (*c_func)(int*) = static_cast<decltype(c_func)>(Callback<void(int*)>::callback);
// Use in any way you wish.
std::unique_ptr<int> iptr{new int(5)};
c_func(iptr.get());
}
回答by Thomas Fankhauser
@Snps answer is great. I extended it with a maker function that creates a callback, as I always use void
callbacks without parameters:
@Snps 的回答很棒。我使用创建回调的 maker 函数对其进行了扩展,因为我总是使用void
不带参数的回调:
typedef void (*voidCCallback)();
template<typename T>
voidCCallback makeCCallback(void (T::*method)(),T* r){
Callback<void()>::func = std::bind(method, r);
void (*c_function_pointer)() = static_cast<decltype(c_function_pointer)>(Callback<void()>::callback);
return c_function_pointer;
}
From then on, you can create your plain C callback from within the class or anywhere else and have the member called:
从那时起,您可以从类内或其他任何地方创建纯 C 回调,并调用该成员:
voidCCallback callback = makeCCallback(&Foo::print, this);
plainOldCFunction(callback);
回答by Evgeniy Alexeev
@Snps answer is perfect! But as @DXM mentioned it can hold only one callback. I've improved it a little, now it can keep many callbacks of the same type. It's a little bit strange, but works perfect:
@Snps 答案是完美的!但正如@DXM 提到的,它只能容纳一个回调。我对它进行了一些改进,现在它可以保留许多相同类型的回调。这有点奇怪,但效果很好:
#include <type_traits>
template<typename T>
struct ActualType {
typedef T type;
};
template<typename T>
struct ActualType<T*> {
typedef typename ActualType<T>::type type;
};
template<typename T, unsigned int n,typename CallerType>
struct Callback;
template<typename Ret, typename ... Params, unsigned int n,typename CallerType>
struct Callback<Ret(Params...), n,CallerType> {
typedef Ret (*ret_cb)(Params...);
template<typename ... Args>
static Ret callback(Args ... args) {
func(args...);
}
static ret_cb getCallback(std::function<Ret(Params...)> fn) {
func = fn;
return static_cast<ret_cb>(Callback<Ret(Params...), n,CallerType>::callback);
}
static std::function<Ret(Params...)> func;
};
template<typename Ret, typename ... Params, unsigned int n,typename CallerType>
std::function<Ret(Params...)> Callback<Ret(Params...), n,CallerType>::func;
#define GETCB(ptrtype,callertype) Callback<ActualType<ptrtype>::type,__COUNTER__,callertype>::getCallback
Now you can just do something like this:
现在你可以做这样的事情:
typedef void (cb_type)(uint8_t, uint8_t);
class testfunc {
public:
void test(int x) {
std::cout << "in testfunc.test " <<x<< std::endl;
}
void test1(int x) {
std::cout << "in testfunc.test1 " <<x<< std::endl;
}
};
cb_type* f = GETCB(cb_type, testfunc)(std::bind(&testfunc::test, tf, std::placeholders::_2));
cb_type* f1 = GETCB(cb_type, testfunc)(
std::bind(&testfunc::test1, tf, std::placeholders::_2));
f(5, 4);
f1(5, 7);
回答by stands2reason
The short answer is: you can convert a member function pointer to an ordinary C function pointer using std::mem_fn.
简短的回答是:您可以使用std::mem_fn将成员函数指针转换为普通的 C 函数指针。
That is the answer to the question as given, but this question seems to have a confused premise, as the asker expects C code to be able to call an instance method of MainWindow without having a MainWindow*, which is simply impossible.
这就是给出的问题的答案,但是这个问题似乎有一个混淆的前提,因为提问者希望 C 代码能够在没有 MainWindow* 的情况下调用 MainWindow 的实例方法,这根本不可能。
If you use mem_fn to cast MainWindow::on_btn_clicked
to a C function pointer, then you still a function that takes a MainWindow*
as its first argument.
如果您使用 mem_fn 转换MainWindow::on_btn_clicked
为 C 函数指针,那么您仍然是一个将 aMainWindow*
作为其第一个参数的函数。
void (*window_callback)(MainWindow*,int*) = std::mem_fn(&MainWindow::on_btn_clicked);
That is the answer to the question as given, but it doesn't match the interface. You would have to write a C function to wrap the call to a specific instance (after all, your C API code knows nothing about MainWindow or any specific instance of it):
这是给出的问题的答案,但它与界面不匹配。您必须编写一个 C 函数来包装对特定实例的调用(毕竟,您的 C API 代码对 MainWindow 或其任何特定实例一无所知):
void window_button_click_wrapper(int* arg)
{
MainWindow::inst()->on_btn_clicked(arg);
}
This is considered an OO anti-pattern, but since the C API knows nothing about your object, it's the only way.
这被认为是 OO 反模式,但由于 C API 对您的对象一无所知,因此这是唯一的方法。
回答by user1095108
I've got an idea (not entirely standard-compliant, as extern "C"
is missing):
我有一个想法(不完全符合标准,因为extern "C"
缺少):
class MainWindow;
static MainWindow* instance;
class MainWindow
{
public:
MainWindow()
{
instance = this;
registerCallback([](int* arg){instance->...});
}
};
You will have problems if multiple instances of MainWindow
are instantiated.
如果实例MainWindow
化了多个实例,则会出现问题。