传递给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被传递回回调.