使用包含来自托管代码的指针的 Fortran 类型
Working with a Fortran type containing pointer from managed code
我要使用 Fortran DLL,其中包含具有以下签名(简化)的类型:
TYPE MyType
INTEGER(4) :: ii
REAL(8) :: rr
INTEGER(4) :: n_a0
INTEGER(4) :: n_a1
INTEGER(4), POINTER :: a0(:)
REAL(8) , POINTER :: a1(:)
END TYPE
显然,此类型包含指向整数和双精度数的指针。我从另一个 Fortran 代码通过以下方法顺利访问此类型。
SUBROUTINE MySub(x)
TYPE(MyType) :: x
我的目标是通过 C# 代码使用 MyType
和 MySub
。为此,我在 C# 代码中定义了一个结构,如下所示:
struct MyType
{
public int ii;
public double rr;
public int n_a0;
public int n_a1;
public int[] a0;
public double[] a1;
}
并使用以下方法访问它:
[DllImport("my_test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MySub(ref MyType t);
问题是当MySub
访问非数组成员时一切正常。但是当它尝试访问数组元素时,我得到 AccessViolationException
。我应该怎么做才能解决这个问题?
Fortran 指针不是 C 指针。它们不能与 C 指针互操作。
虽然指向标量的 Fortran 指针通常只是底层地址,但数组指针并非如此。数组指针使用数组描述符,因为数组可以是不连续的,并且指针还包含有关下限和上限的信息。
您应该创建另一个 Fortran 类型,它是 bind(C)
并且包含 C 指针 type(c_ptr)
(在内部模块 iso_c_binding
中定义)。
然后你必须创建原始类型和新类型之间的转换并使用
设置 C 指针
c_interoperable_type%c_a0 = c_loc(old_type%a0(1))
我这里用的是第一个元素,因为数组可能无法互操作。但是,您必须自己确保数组是连续的。
如果您真的无法更改 Fortran 代码,那您就有麻烦了。当然可以找出数组地址在数组描述符中的位置并直接从 C 中使用它。但是我不推荐它,它将特定于编译器,甚至可能特定于版本。
我要使用 Fortran DLL,其中包含具有以下签名(简化)的类型:
TYPE MyType
INTEGER(4) :: ii
REAL(8) :: rr
INTEGER(4) :: n_a0
INTEGER(4) :: n_a1
INTEGER(4), POINTER :: a0(:)
REAL(8) , POINTER :: a1(:)
END TYPE
显然,此类型包含指向整数和双精度数的指针。我从另一个 Fortran 代码通过以下方法顺利访问此类型。
SUBROUTINE MySub(x)
TYPE(MyType) :: x
我的目标是通过 C# 代码使用 MyType
和 MySub
。为此,我在 C# 代码中定义了一个结构,如下所示:
struct MyType
{
public int ii;
public double rr;
public int n_a0;
public int n_a1;
public int[] a0;
public double[] a1;
}
并使用以下方法访问它:
[DllImport("my_test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MySub(ref MyType t);
问题是当MySub
访问非数组成员时一切正常。但是当它尝试访问数组元素时,我得到 AccessViolationException
。我应该怎么做才能解决这个问题?
Fortran 指针不是 C 指针。它们不能与 C 指针互操作。
虽然指向标量的 Fortran 指针通常只是底层地址,但数组指针并非如此。数组指针使用数组描述符,因为数组可以是不连续的,并且指针还包含有关下限和上限的信息。
您应该创建另一个 Fortran 类型,它是 bind(C)
并且包含 C 指针 type(c_ptr)
(在内部模块 iso_c_binding
中定义)。
然后你必须创建原始类型和新类型之间的转换并使用
设置 C 指针c_interoperable_type%c_a0 = c_loc(old_type%a0(1))
我这里用的是第一个元素,因为数组可能无法互操作。但是,您必须自己确保数组是连续的。
如果您真的无法更改 Fortran 代码,那您就有麻烦了。当然可以找出数组地址在数组描述符中的位置并直接从 C 中使用它。但是我不推荐它,它将特定于编译器,甚至可能特定于版本。