很久之前就测试过fortran和c#的混编,找了不少参考资料,自以为学的差不多,今天却发现了新的问题。
很多文献上都会提到,fortran默认是引用传递,c#默认是值传递,在传递多维数组的时候要注意内存行列的优先。结果今天的问题却出在了一维数组上。
假如在fortran中有如下的子例程
SUBROUTINE TEST(Y,M)
!...INTEGER::M
REAL(KIND=4)::Y(M)
PRINT*,Y
RETURN
ENDSUBROUTINE
例子是给fortran传递一个一维的数组,并且告诉fortran这个数组的长度由于强调了按引用传递,可能就会在c#中写出如下的代码:
[DllImport(DllPath, CallingConvention = CallingConvention.StdCall)]
unsafe public static extern void TEST(ref float[] Y,ref M);
可是,这样的代码,却是无法运行成功的,运行时会提示,尝试读取或者写入被保护的内存。
这就是纠结了整整一个下午的问题,不管是去掉ref还是加上ref,还是修改fortran数组的下标,总之,所有该注意的地方几乎都试过了N遍,问题依然存在。
最后决定找出彭国伦的教材,仔细看了一遍vb中的调用方法,发现是传递了数组的首地址,而这个难道在c#中不是用ref吗? 这时候才突然想起,c#中的数组默认就是按引用传递的,
例如
float[] a=new float[5];
float[] b=a;
实际上b只是指向a的地址,并没有真正复制a的内容
如果是
float b=10;
float a=b;
那么a就是获得了b的内容,而不是地址。
这样看来,问题还是出在参数的传递上。数组传递的时候不需要ref,基本类型传递的时候才需要指定按地址传递,修改如下:
unsafe public static extern int TEST(float[] Y,ref M);
终于正常了。赶紧记下来,免得下次忘记!