如何将C ++回调传递给C库函数?

时间:2012-05-17 16:39:11

标签: c++ c visual-c++ casting

我正在使用C ++开发代码,并希望使用MPFIT非线性曲线拟合库,它是用C开发的,但允许用C ++编译。

例如我有一个名为“myClass”的类,这个类有一个函数myClass :: Execute()

我在myClass.h文件中包含“mpfit.h”。并尝试从Execute()调用一个名为mpfit的函数。

int status = mpfit(ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);

问题是ErrorFunction是myClass的一个功能。所以编译器在我尝试使用它时会出错。我试图从类对象中携带Erro​​rFunction,但这次我采取了下面给出的错误:

ErrorFunction在类之外时出错:

  

错误4错误C2664:'mpfit':无法从'int转换参数1   (__cdecl *)(int,int,double *,double,double *,void *)'to   'mp_func'

ErrorFunction在类中时出错:

Error   3   error C3867: 'myClass::ErrorFunction': function call missing argument list; use '&myClass::ErrorFunction' to

错误函数的定义:

int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)

如何调用此函数并将其解析为mpfit,这是一个C函数?

mp_func定义为:

/* Enforce type of fitting function */
typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
               int n, /* Number of variables (elts of x) */
               double *x,      /* I - Parameters */
               double *fvec,   /* O - function values */
               double **dvec,  /* O - function derivatives (optional)*/
               void *private_data); /* I/O - function private data*/

5 个答案:

答案 0 :(得分:3)

根据您显示的mpfit()mp_func的定义,您需要使用private_data的{​​{1}}参数来传递您的班级mp_func指针周围。您当前正在使用该参数来传递this项目。让variables成为您班级的成员(如果尚未加入),然后将variables传递给this

mpfit()

或者:

class MyClass
{
private:
    TheDataType variables;
    static int ErrorFunction(int m, int n, double *x, double *fvec, double **dvec, MyClass *pThis);
public:
    void DoIt();
};

void MyClass::DoIt()
{
    // ...
    int status = mpfit((mp_func)&ErrorFunction, num1, num2, xsub_1D, 0, 0, this, &result); 
    // ...
}

int MyClass::ErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
    // use pThis->variables as needed ...
} 

答案 1 :(得分:3)

确保您的通话约定匹配。 C库使用C调用约定或cdecl(__ cdecl)。如果你在C ++中使用mp_func typedef,它可能默认为编译器的标准调用约定或stdcall(__stdcall)。创建一个新的typedef或将其更改为以下内容:

typedef int __cdecl (*mp_func)(int m, /* Number of functions (elts of fvec) */
               int n, /* Number of variables (elts of x) */
               double *x,      /* I - Parameters */
               double *fvec,   /* O - function values */
               double **dvec,  /* O - function derivatives (optional)*/
               void *private_data); /* I/O - function private data*/

当您声明ErrorFunction时,也将其声明为__cdecl:

int __cdecl ErrorFunction(int, int, double*, double *, double **, void *);

如果编译器在调用mpfit函数时仍然抱怨,您可以尝试使用cdecl将函数指针强制转换为mp_func typedef:

int status = mpfit((mp_func)ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);

答案 2 :(得分:1)

看起来不是:

int ErrorFunction(int dummy1, int dummy2, double* xsub, double diff, double *dvec, void *vars)

它应该是:

int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)

匹配您的

typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
               int n, /* Number of variables (elts of x) */
               double *x,      /* I - Parameters */
               double *fvec,   /* O - function values */
               double **dvec,  /* O - function derivatives (optional)*/
               void *private_data); /* I/O - function private data*/

答案 3 :(得分:1)

您的回调必须声明extern "C"才能生效。

编辑:我看到人们很难掌握这个事实。标准说(7.5 / 1):

  

具有不同语言链接的两种函数类型是不同的类型   即使他们是相同的。

答案 4 :(得分:0)

使用pimpl习语,有一个C ++ - to - C的标准习语:

foo_c.h:

#ifdef __cplusplus
extern "C" {
#endif
//forward declaration.  clients of foo_c.h should only hold pointers to Foo_c
typedef struct Foo_c Foo_c;

int someMethod(Foo_c* foo);
#ifdef __cplusplus
}
#endif

foo_c.cpp:

#include <foo.h>
struct Foo_c {
       Foo foo;
}
int someMethod(Foo_c* foo) { 
     try {
         foo->foo.someMethod();
         return 0; //no error
     }
     catch(...) {
         return 1; //error
     }
}

(根据以下答案编辑为外部“C”。)