首页 > 解决方案 > 如何使用 C++ 函数指针作为 C 函数指针/回调的参数

问题描述

我确实知道 C++ lambda 或 C 函数指针,但我不知道如何将它们混合在一起。我已经找到了Mixing C++ instance methods with C callback functions,但它不依赖于我的需要。

我有一个包含 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? */
   );

}
};

“Cliente”类是这样的:

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;

};

Cliente.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);
}
};

我省略了其余的实现,因为它不相关。我也不是在问 lib jack。重点是如何将 C++ 函数作为参数传递给 C 回调,如上所示。

标签: c++ccallbackfunction-pointers

解决方案


注意jack_set_process_callback() 的最后一个参数是 a void *,它被传递给回调函数。

这是 C 库的一种常见设计模式,可以使它们与 C++ 一起使用。

您要做的是传递this您希望调用其方法的对象,作为回调,void *将回调指针指向一个extern "C"链接包装函数,该函数接受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当然,当回调被调用时,你要确保它仍然存在并且是一个有效的对象。


推荐阅读