如何使用C++函数指针作为指向 C 函数指针/回调的参数
How to use C++ Function Pointer as Parameter to a C Funcion Pointer/Callback
我知道C++lambdas或C函数指针,但我不知道如何将它们混合在一起。我已经找到了 将C++实例方法与 C 回调函数混合在一起,但它不依赖于我的需求。
我有一个包含 C 标头的C++类,如下所示:
extern "C" {
#include <jack/jack.h>
#include <jack/types.h`enter code here`>
#include <jack/ringbuffer.h>
#include <jack/midiport.h>
}
#include <QDialog>
#include <QFile>
#include <QString>
#include "Cliente.h"
class FormQStudio : public QDialog
{
Q_OBJECT
public:
explicit FormQStudio(QWidget *parent = nullptr);
~FormQStudio();
void playMIDIFile(QString file) noexcept(false);
int theCallback(jack_nframes_t nframes, void *arg);
};
C 标头定义了一些类型:
typedef uint32_t jack_nframes_t;
typedef int (*JackProcessCallback)(jack_nframes_t nframes, void *arg);
int jack_set_process_callback (jack_client_t *client,
JackProcessCallback process_callback,
void *arg) JACK_OPTIONAL_WEAK_EXPORT;
我的C++类的实现需要将theCallback(jack_nframes_t nframes, void *arg)
作为参数传递给C函数jack_set_process_callback
。但我不知道该怎么做。
#include "FormQStudio.h"
FormQStudio::FormQStudio(QWidget *parent) :
QDialog(parent),
ui(new Ui::FormQStudio)
{
ui->setupUi(this);
}
void FormQStudio::playMIDIFile(QString file) noexcept(false){
smf_t *smf = smf_load(file.toUtf8());
smf_event_t *event;
Cliente *c = new Cliente("QStudio");
c->inicializarCliente(
/* HOW TO REFERENCE this->processJackCallback as a parameter? */
);
}
};
类"客户"是这样的:
extern "C" {
#include <jack/jack.h>
#include <jack/types.h>
#include <jack/ringbuffer.h>
#include <jack/midiport.h>
}
#include <QString>
#include <QMap>
#include "ClientePorta.h"
#include "QStageException.h"
class Cliente
{
public:
Cliente(QString clientName);
struct MidiMessage {
jack_nframes_t time;
int len; /* Length of MIDI message, in bytes. */
unsigned char data[3];
};
jack_client_t *getClient();
void conectar(QString portaOrigem, QString clienteDestino, QString portaDestino) noexcept(false);
void inicializarCliente(JackProcessCallback callback) noexcept(false);
void addClientePorta(ClientePorta * cp);
ClientePorta* getClientePorta(QString nomePorta);
void sendMIDI(QString outputPortName, jack_nframes_t nframes ) noexcept(false);
private:
QString clientName;
QString inputPortName;
QString outputPortName;
QMap<QString,ClientePorta*> portas;
jack_client_t *jackClient = NULL;
};
客户.cpp是:
#include "Cliente.h"
#include <QDebug>
Cliente::Cliente(QString clientName)
{
this->clientName = clientName;
}
void Cliente::inicializarCliente(JackProcessCallback callback) noexcept(false){
jackClient = jack_client_open(clientName.toUtf8().data(), JackNoStartServer, NULL);
int err = jack_set_process_callback(jackClient, callback , this);
}
};
我省略了实现的其余部分,因为它不相关。我也不是在问自由杰克。重点是如何将C++函数作为参数传递给 C 回调,如上所示。
FormQStudio::theCallback
不是一个函数。它是一个非静态成员函数,这意味着它只能通过FormQStudio
类型的对象调用,该对象指向该对象的指针作为this
传递给函数。
C 对C++类或类成员一无所知。所以它不能调用这样的函数。
此外,应用于FormQStudio::theCallback
的&
运算符会产生一个"指向成员函数的指针"(PMF),它与指向函数的指针完全不同。(这可能就是您看到编译器错误的原因,尽管很难确切地知道您从问题中的代码示例中尝试了什么。因此,即使C++程序也不能将其用作独立的回调,尽管它们可以使用.*
/->*
语法通过提供的类intance对象引用/指针来调用它。(注意:现在最好使用std::invoke
而不是相当晦涩的运算符。
如果事实证明FormQStudio::theCallback
实际上根本没有使用this
,那就让它static
。然后,您可以获取其地址并将其用作函数指针。(尽管我认为不能保证 C 和 C++ 函数具有相同的调用约定,因此可以想象,将其传递给期望回调的 C 函数时仍然会遇到问题。
注意jack_set_process_callback
()的最后一个参数是一个void *
,它被传递给回调函数。
这是 C 库的常见设计模式,用于使其可用于C++。
您要做的是将要调用其方法的对象的this
作为回调传递给带有回调指针的extern "C"
void *
,该函数采用void *
,然后将其reinterpret_cast
回类实例指针,然后调用其方法, 像这样:
extern "C" {
int fwd_callback(jack_nframes_t nframes, void *arg)
{
FormQStudio *p=reintrerpret_cast<FormQStudio *>(arg);
return p->theCallback(nframes);
}
};
// ...
FormQStudio *some_object;
// ...
jack_set_process_callback(client, fwd_callback, reinterpret_cast<void *>(some_object));
当然,当调用回调时,您需要确保some_object
仍然存在并且是有效的对象。
- 如何正确编写指针函数声明?
- C++常规指针函数或模板
- 如何重新定义 C++ 指针函数?
- C++ 指向其他类函数的指针函数
- 指针到指针函数参数
- 将指向成员的指针函数传递到模板中
- C++ 在 none 常量指针函数中返回一个常量指针
- 如何使用指针函数编写/读取数组
- 是C 中的函数指针函数对象
- 如何从另一个类调用指向成员的指针函数
- 如何声明采用指向成员的指针函数的函数
- 如何构造一个以可变参数指针函数作为成员的类?
- c 通过值或指针函数语法
- 将typedef方法作为指针函数传递
- 从 Main 中的双指针函数打印出指针数组
- strcpy 对指针函数的引用
- 这是否仍然声明一种指针函数的别名?
- 将指向成员的指针函数与 std::shared_ptr 结合使用
- 'Incomplete type' 为标准::函数声明指向成员的指针函数模板参数时出错
- 从注入进程的 DLL 调用函数并更改指针函数的地址