This is kind of a follow up to this question.
I have a fortran user defined type (TYPE(contactside)) that contains some values and some fixed size arrays, as well as an exported function that uses this structure as input arguments. Now I want to call this function from c#. I am able to create fixed sized arrays in a struct (ContactSide) and it works just fine. I can pass the arrays to fortran
My question is, is it possible to do this without resorting to unsafe code? With just regular dynamic C# arrays double[] radius instead of fixed double radius[MaxSize]. When I tried it without any [MarshalAs()] specifications, I get garbage:
Fortan
module contacts
use ISO_C_BINDING
implicit none
integer, parameter :: max_size = 3600;
type, bind(c) :: contactside
INTEGER(c_int) :: n
REAL(c_double) :: elasticity, poisson
REAL(c_double) :: radius(max_size), crown(max_size)
end type
contains
! FUNCTIONS/SUBROUTINES exported from dll:
subroutine Hertz(load, side1, side2) bind(c)
implicit none
!DEC$ ATTRIBUTES DLLEXPORT::Hertz
! Arguments
REAL(c_double),value,intent(in) :: load
TYPE(contactside),intent(in) :: side1, side2
! Implementation omitted
end subroutine Hertz
end module
C#
public unsafe struct ContactSide
{
const int MaxSize = 3600;
int size;
double elasticity, poisson;
fixed double radius[MaxSize], crown[MaxSize];
public ContactSide(double radius, double crown) : this(new double[] { radius }, crown) { }
public ContactSide(double[] radius, double crown)
{
this.size=radius.Length;
fixed (double* ptr1 = this.radius, ptr2 = this.crown)
{
for(int i = 0; i<size; i++)
{
ptr1[i]=radius[i];
ptr2[i]=crown;
}
}
this.elasticity=DefaultElasticity;
this.poisson=DefaultPoisson;
}
public static double DefaultElasticity = 200000;
public static double DefaultPoisson = 0.3;
}
class Program
{
[DllImport("FortranContacts.dll", EntryPoint = "hertz", CallingConvention = CallingConvention.Cdecl)]
public extern static void Hertz(double load, ref ContactSide side1, ref ContactSide side2);
static void Main(string[] args)
{
ContactSide side1 = new ContactSide(8.0, 1200);
ContactSide side2 = new ContactSide(new double[] { 22, 22.2, 22.8, 24.6, 25.8, 29.3 }, 10000);
Hertz(1000, ref side1, ref side2);
}
}
and here is the failed attempt at a plain (not unsafe) structure:
public struct ContactSide
{
int size;
double elasticity, poisson;
double[] radius, crown;
public ContactSide(double radius, double crown) : this(new double[] { radius }, crown) { }
public ContactSide(double[] radius, double crown)
{
this.size=radius.Length;
this.radius=new double[size];
this.crown=new double[size];
radius.CopyTo(this.radius, 0);
this.crown= Enumerable.Repeat(crown, size).ToArray();
this.elasticity=DefaultElasticity;
this.poisson=DefaultPoisson;
}
public static double DefaultElasticity = 200000;
public static double DefaultPoisson = 0.3;
}
NOTES: I am using VS2015 with Intel Fortran XE on Win7-64bit


use ISO_C_BINDINGand declared my types asINTEGER(c_int)andREAL(c_double), but nothing changed. Oh, I also changed the declaration totype, bind(c) :: contactside.monoon my computer and tried combining C# with gfortran (by googling a lot :) If I define a struct containing bare C-pointers and pass the struct to Fortran routines, I could read/modify the values of the arrays using c_f_pointer(). But if I include double[] etc in the struct, mymonofailed with segfault (even if I include bare-C pointer together with dynamic C# arrays). So, the compiler seems unhappy with double[] in the struct... Also, if I use bare C-pointers, the code needs to be specifiedunsafe.