从double数组转换为指针

时间:2010-03-10 06:46:56

标签: c# interop

我有这样的课程

public unsafe class EigenSolver
{
   public double* aPtr
   {get; private set;}
   public EigenSolver(double* ap)
   {
      aPtr = ap;
   }
   public EigenSolver(double[] aa)
   {
     // how to convert from aa double array to pointer?
   }

   public void Solve()
   {
     Interop.CallFortranCode(aPtr);
   }
}

你可以猜到,我需要从double数组转换为指针。怎么做?

注意:互操作函数Interop.CallFortranCode(double* dPtr)是我无法改变的。

注意2:两个构造函数都是必需的,因为我的一些API用户想要传入指针,有些人想要传入数组。我不能强迫他们选择。

2 个答案:

答案 0 :(得分:9)

使用fixed声明:

fixed (double* aaPtr = aa) {
   // You can use the pointer in here.
}

fixed的上下文中,变量的内存被固定,因此垃圾收集器不会尝试移动它。

我会改用这种方法:

public class EigenSolver
{
   public double[] _aa;
   /*
   There really is no reason to allow callers to pass a pointer here, 
   just make them pass the array.
   public EigenSolver(double* ap)
   {
      aPtr = ap;
   }
   */
   public EigenSolver(double[] aa)
   {
     _aa = aa;
   }

   public void Solve()
   {
     unsafe {
        fixed (double* ptr = _aa) {
           Interop.CallFortranCode(ptr);
        }
     }
   }
}

这假定CallFortranCode当然不会尝试在调用之外使用指针。一旦fixed语句超出范围,指针就不再有效了......

更新:

您无法获取参数double[] aa的地址并将其存储在您的实例字段中。即使编译器会让你,GC也必然会移动那个内存,让你的指针无用。

您可以这样做:使用Marshal.AllocHGlobal分配足够的内存来存储数组的所有元素(aa.Length * sizeof(double)))。然后,使用Marshal.Copy将数组的内容复制到新分配的内存中:

bool _ownsPointer; 
public EigenSolver(double[] aa) {
   IntPtr arrayStore = (double*)Marshal.AllocHGlobal(aa.Length * sizeof(double));
   Marshal.Copy(aa, 0, arrayStore, aa.Length);
   this.aPtr = (double*)arrayStore.ToPointer();
   _ownsPointer = true;
}

~EigenSolver {
   if (_ownsPointer) {
      Marshal.FreeHGlobal(new IntPtr(this.aPtr));
   }
}

希望这有效......

安德鲁

答案 1 :(得分:1)

虽然fixed确实是您正在寻找的答案,但您无法以您尝试的方式使用它。一旦fixed块结束(在右括号处),指针就会失效。所以你不能在构造函数中使用它来存储指针。您也不应该这样做,因为在内存中长时间固定托管对象会导致性能急剧下降。

我要做的是将数组(作为托管对象)传递给Solve函数。通过这种方式,您可以将其固定下来以便进行Fortran互操作,然后让gc处理它。