传递给lmdif1的第二个和第三个参数是整数,对于我的测试,顺序中的值是12和9.现在当它们在C代码中时,12的值现在是9而9的值在308000之间变化和912000.不知道为什么.
首先,我想知道我使用的签名是否有效
C#签名:
[DllImport("cminpack_dll.dll",CallingConvention = CallingConvention.Cdecl)] public static extern int lmdif1(IntPtr fcn,int m,int n,double[] x,double[] fVec,double tol,int[] iwa,double[] wa,int lwa);
C签名:
int __cminpack_func__(lmdif1)(__cminpack_decl_fcn_mn__ void *p,real *x,real *fvec,real tol,int *iwa,real *wa,int lwa)
我称之为:
//All of the variables passed in match the types in C# signature above. var info =lmdif1( functionPointer,pointsetLength,initialGuessLength,initialGuess,fVec,tol,iwa,wa,lwa);
现在这是我第一次与PInvoke打交道,而我的C并不好,之前从未真正做过,所以任何帮助都会很棒.我怀疑我可能需要制造一些东西,但我已经尝试过将I4和U4作为整体进行编组,它仍然会做同样的事情.
为你的帮助提前干杯.
编辑:
以下是描述C函数的注释,如果有帮助:
/* ********** */ /* subroutine lmdif1 */ /* the purpose of lmdif1 is to minimize the sum of the squares of */ /* m nonlinear functions in n variables by a modification of the */ /* levenberg-marquardt algorithm. this is done by using the more */ /* general least-squares solver lmdif. the user must provide a */ /* subroutine which calculates the functions. the jacobian is */ /* then calculated by a forward-difference approximation. */ /* the subroutine statement is */ /* subroutine lmdif1(fcn,m,n,x,fvec,info,lwa) */ /* where */ /* fcn is the name of the user-supplied subroutine which */ /* calculates the functions. fcn must be declared */ /* in an external statement in the user calling */ /* program,and should be written as follows. */ /* subroutine fcn(m,iflag) */ /* integer m,iflag */ /* double precision x(n),fvec(m) */ /* ---------- */ /* calculate the functions at x and */ /* return this vector in fvec. */ /* ---------- */ /* return */ /* end */ /* the value of iflag should not be changed by fcn unless */ /* the user wants to terminate execution of lmdif1. */ /* in this case set iflag to a negative integer. */ /* m is a positive integer input variable set to the number */ /* of functions. */ /* n is a positive integer input variable set to the number */ /* of variables. n must not exceed m. */ /* x is an array of length n. on input x must contain */ /* an initial estimate of the solution vector. on output x */ /* contains the final estimate of the solution vector. */ /* fvec is an output array of length m which contains */ /* the functions evaluated at the output x. */ /* tol is a nonnegative input variable. termination occurs */ /* when the algorithm estimates either that the relative */ /* error in the sum of squares is at most tol or that */ /* the relative error between x and the solution is at */ /* most tol. */ /* info is an integer output variable. if the user has */ /* terminated execution,info is set to the (negative) */ /* value of iflag. see description of fcn. otherwise,*/ /* info is set as follows. */ /* info = 0 improper input parameters. */ /* info = 1 algorithm estimates that the relative error */ /* in the sum of squares is at most tol. */ /* info = 2 algorithm estimates that the relative error */ /* between x and the solution is at most tol. */ /* info = 3 conditions for info = 1 and info = 2 both hold. */ /* info = 4 fvec is orthogonal to the columns of the */ /* jacobian to machine precision. */ /* info = 5 number of calls to fcn has reached or */ /* exceeded 200*(n+1). */ /* info = 6 tol is too small. no further reduction in */ /* the sum of squares is possible. */ /* info = 7 tol is too small. no further improvement in */ /* the approximate solution x is possible. */ /* iwa is an integer work array of length n. */ /* wa is a work array of length lwa. */ /* lwa is a positive integer input variable not less than */ /* m*n+5*n+m. */ /* subprograms called */ /* user-supplied ...... fcn */ /* minpack-supplied ... lmdif */ /* argonne national laboratory. minpack project. march 1980. */ /* burton s. garbow,kenneth e. hillstrom,jorge j. more */ /* ********** */ /* check the input parameters for errors. */
解决方法
所以,这就是我所做的.我下载了库并通过C预处理器传递了lmdif1.c文件,因此扩展了宏.我使用了mingw编译器中的那个.它产生了以下输出:
int __attribute__((__dllexport__)) lmdif1(cminpack_func_mn fcn_mn,void *p,double *x,double *fvec,double *wa,int lwa);
然后看一下cminpack_func_mn的定义,我们有:
typedef int (*cminpack_func_mn)(void *p,const double *x,int iflag);
所以lmdif1接收到一个额外的void指针.由于函数指针类型cminpack_func_mn也接收到具有相同非描述名称的void指针,我准备打赌你传递给lmdif1的指针被传递回你的回调函数fcn_mn.此机制通常用于允许库的使用者编写可以访问额外状态的回调函数.
如果您不需要它,并且您肯定不会使用C#委托,则可以传递IntPtr.Zero并忽略回调中的值.
要解决此问题,您需要进行三项更改:
>将void指针添加到lmdif1的C#声明中.
>将void指针添加到回调委托的C#声明,以及实现回调的函数.
>将IntPtr.Zero传递给lmdif1的额外void指针参数.
我不确定你为什么把你的回调参数声明为IntPtr.您可以在此处使用委托类型,也可以使用UnmanagedFunctionPointer属性来强制执行Cdecl.
更新:为了完整性,我深入研究了lmdif1的实现,并研究了如何调用回调.是的,如上所述,void指针p被传递回回调.