I am to use a Fortran DLL which contains a type with following signature (simplified):
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
Obviously, this type contains pointers to integers and doubles. I access this type through the following method from another Fortran code smoothly.
SUBROUTINE MySub(x)
TYPE(MyType) :: x
My goal is to work with that MyType
and MySub
through C# code. To do so, I defined a structure in my C# code as follows:
struct MyType
{
public int ii;
public double rr;
public int n_a0;
public int n_a1;
public int[] a0;
public double[] a1;
}
and access it with the following method:
[DllImport("my_test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MySub(ref MyType t);
The problem is when MySub
accesses non-array members everything is OK. But when it tries to access array elements I get AccessViolationException
. What should I do to solve this problem?
Fortran pointers are not C pointers. They are not interoperable with C pointers.
While Fortran pointers to scalars are often just addresses under the hood, this is not the case for array pointers. Array pointers use array descriptors, because the arrays can be non-contiguous and the pointer also contains the information about the lower and the upper bound.
You should create another Fortran type which is bind(C)
and which contains C pointers as type(c_ptr)
(defined in the intrinsic module iso_c_binding
).
Then you have to create a conversion between the original type and the new type and set the C pointers using
c_interoperable_type%c_a0 = c_loc(old_type%a0(1))
I use the first element here, because the array may not be interoperable. However, you must make sure yourselves that the array is simply contiguous.
If you really cannot change the Fortran code you are in trouble. It is certainly possible to find out where the array address lies in the array descriptor and use it directly from C. However I cannot recommend it, it will be compiler specific and perhaps even version specific.