2012-12-10 37 views
1

我有一个C库,这个函数返回4个输出参数调用:的P/Invoke期间编组输出指针从C#到C

void __declspec(dllexport) demofun(double a[], double b[], double* output1, double* output2, double res[], double* output3) 

而且我写了一个C#包装调用的函数:

namespace cwrapper 
{ 
    public sealed class CWRAPPER 
    {  
     private CWRAPPER() {} 

     public static void demofun(double[] a, double[] b, double output1, 
          double output2, double[] res, double output3) 
     { // INPUTS: double[] a, double[] b 
      // OUTPUTS: double[] res, double output1, double output2 
      // Arrays a, b and res have the same length 
      // Debug.Assert(a.length == b.length) 

      int length = a.Length; 
      CWRAPPERNative.demofun(a, b, length, ref output1, ref output2, 
         res, ref output3); 
     } 
    } 

    [SuppressUnmanagedCodeSecurity] 
    internal sealed class CWRAPPERNative 
    { 
     private CWRAPPERNative() {} 

     [DllImport("my_cwrapper.dll", CallingConvention=CallingConvention.Cdecl, 
      ExactSpelling=true, SetLastError=false)] 
     internal static extern void demofun([In] double[] a, [In] double[] b, 
          int length, ref double output1, ref double output2, 
          [Out] double[] res, ref double output3); 
    } 
} 

当我拨打CWRAPPERNative.demofun方法时,一切正常。但是,当我拨打CWRAPPER.demofun方法时,只有double[] res正确传递。调用后输出参数output1,output2output3不变。

// ... 
// Initializing arrays A and B above here 

double[] res = new double[A.Length]; 
double output1 = 0, output2 = 0, output3 = 0; 

// Works partially: output1 to 3 unchanged 
CWRAPPER.demofun(A, B, output1, output2, res, output3); 

// Works correctly: all outputs are changed 
CWRAPPERNative.demofun(A, B, A.Length, ref output1, ref output2, res, ref output3); 

我猜我是错误地编组指针参数,但我找不出修复。任何人都知道解决方案谢谢!

回答

1

您忘记通过引用传递demofun内的值:

public static void demofun(double[] a, double[] b, ref double output1, 
    ref double output2, double[] res, ref double output3) 

的值是本方法的内变化,但不被修改为原始调用者。

+0

解决了问题!但是,与CWRAPPERNative.demofun相比,现在看来只是为了消除冗长的争论而不便。也许我应该只是通过一个结构传递输出,所以它更干净? CWRAPPER.demofun的时间比CWRAPPERNative.demofun的平均时间多出10000多次。这似乎是一个微不足道的问题,因为我们正在谈论微秒,但是要记住,我正在与C进行互动以利用AVX/SSE内在函数。你会如何优化这个?我想听听你的想法。非常感谢! – elleciel

0

全部double参数到CWRAPPER.demofun是非易失性的,即值不能被该函数改变。要解决这个问题,你需要这样的一个变化:

public static void demofun(double[] a, double[] b, 
    out double output1, out double output2, double[] res, out double output3) 

虽然还有另一个问题。 C函数的第5个参数double res[]是输入参数,但您的P/Invoke声明具有[Out] double[] res(输出参数)。我已经重写了P /调用声明这样的:

[DllImport("my_cwrapper.dll", CallingConvention=CallingConvention.Cdecl, 
    ExactSpelling=true, SetLastError=false)] 
static extern void demofun([In] double[] a, [In] double[] b, [In] int length, 
    [Out] double output1, [Out] double output2, [In] double[] res, [Out] double output3); 

实施例方法与out参数执行; OutOutTester显示具有out参数的方法不需要直接分配它们的值:

public static void OutTester(out int a) 
{ 
    a = 1; 
} 

public static void OutOutTester(out int a, out int b) 
{ 
    OutTester(out a); 
    b = 1; 
} 
+0

我无法在调用方法中使用'out'进行编译,因为out参数必须在控件离开方法之前分配。我觉得进行逻辑的方法是在调用方法中使用'out'并分配临时变量,例如'demtemun'内部的'double temp1 = 0,temp2 = 0,temp3 = 0;'将临时变量传递给'CWRAPPERNative.demofun',然后赋值'output1 = temp1;'等等。但是由于某种原因,输出返回作为0的。 – elleciel

+0

输出从'CWRAPPER.demofun'返回为0,因为这些参数是_non-volatile_。但是'CWRAPPERNative.demofun'中的那些参数会返回为期望值,因为它们是不稳定的,因为'ref'关键字。你可以通过'out'替换'ref'来达到同样的效果,这对代码安全性更好。查看我的更新答案的例子。 – groverboy