我有这样的课程
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用户想要传入指针,有些人想要传入数组。我不能强迫他们选择。
答案 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处理它。