问题描述
subroutine COMPLEX_PASSING(r,i,c)
!DEC$ ATTRIBUTES DLLEXPORT::COMPLEX_PASSING
REAL*8 :: r,i
COMPLEX*8 :: c
c = cmplx((r * 2),(i * 2))
return
end
Fortran 代码是用
编译的gfortran -c complex_passing.f90
gfortran -fPIC -shared -o complex_passing.dll complex_passing.o
using System;
using System.Runtime.InteropServices;
namespace FortranCalling {
class Program {
static void main(string[] args) {
double real = 4;
double imaginary = 10;
COMPLEX c = new COMPLEX();
complex_passing( ref real,ref imaginary,ref c);
Console.WriteLine("Real: {0}\nImaginary: {1}",c.real,c.imaginary);
Console.ReadLine();
}
[StructLayout(LayoutKind.Sequential)]
struct COMPLEX {
public double real;
public double imaginary;
}
[DllImport("complex_passing.dll",EntryPoint = "complex_passing_",CallingConvention = CallingConvention.Cdecl)]
static extern void complex_passing(ref double r,ref double i,ref COMPLEX c);
}
}
收效甚微 - 我的 COMPLEX 结构似乎返回垃圾数据:
Real: 134217760.5
Imaginary: 0
当我期望实部为 8,虚部为 20 时。
解决方法
gfortran 将非标准 COMPLEX*8
视为大小为 8 字节的复数,实部和虚部各为 4 字节。相反,您需要一个 16 字节的复数,实部和虚部各有 8 个字节 (COMPLEX*16
),否则您应该相应地更改 C# 方面。
在gfortran下使用以下内容可以看到其效果:
complex*8 :: c8 = (8d0,20d0)
complex*16 :: c16 = 0
c16%re = TRANSFER(c8,c16)
print*,c8,c16
end
当然,您根本不应该使用 complex*
。使用 complex(kind=..)
可以看到参数不匹配。
考虑以下“Fortran”源:
subroutine s(r,i,c)
real(kind(0d0)) :: r,i
complex(kind(0e0)) :: c
c = cmplx((r*2),(i*2))
end subroutine s
interface ! Interface block required to lie to some versions of gfortran
subroutine s(r,i
complex(kind(0d0)) :: c
end subroutine s
end interface
complex(kind(0d0)) c
call s(4d0,10d0,c)
print*,c%re
end
并将其与 Fortran 源代码进行比较:
subroutine s(r,i
complex(kind(0d0)) :: c
c = cmplx((r*2),(i*2))
end subroutine s
complex(kind(0d0)) c
call s(4d0,c%re
end
此外,除了使用 kind(0d0)
等,还有 iso_fortran_env
的各种 C 互操作性常量和存储大小常量。