1

我正在使用 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 的一个函数。所以当我尝试使用它时编译器会出错。我试图将 ErrorFunction 从类对象中取出,但这次我得到了下面给出的错误:

当 ErrorFunction 在类之外时出错:

错误 4 错误 C2664: 'mpfit' : 无法将参数 1 从 'int (__cdecl *)(int,int,double *,double,double *,void *)' 转换为 '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)

如何调用该函数并将其解析为 C 函数 mpfit?

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

5 回答 5

4

确保您的调用约定匹配。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);
于 2012-05-17T21:42:33.527 回答
3

鉴于您已经展示的mpfit()和的定义mp_func,您需要使用 的private_data参数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 ...
} 

或者:

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

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

int MyClass::MPFitErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
    return pThis->MyErrorFunction(m, n, x, fvec, dvec);
} 

int MyClass::MyErrorFunction(int m, int n, double* x, double *fvec, double **dvec)
{
    // use this->variables as needed ...
} 
于 2012-05-17T16:59:33.570 回答
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*/
于 2012-05-17T16:44:09.473 回答
1

必须声明您的回调才能extern "C"使其正常工作。

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

具有不同语言链接的两个函数类型是不同的类型,即使它们在其他方面相同。

于 2012-05-17T17:01:22.723 回答
0

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

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”编辑。)

于 2012-05-17T16:50:45.500 回答