【发布时间】:2020-03-18 22:49:46
【问题描述】:
我是新手,但我需要从 C 中访问一些旧的 Fortran 77 函数。 如果可能的话,我不想更改 Fortran 代码,我真的更喜欢编写一个包装器来从 C 中调用 Fortran 函数。我希望得到一个最小的工作示例(在 Linux 上)。我做了什么:
在文件 somefunction.f 中:
REAL*8 FUNCTION MYFUNC(ZZ)
IMPLICIT NONE
REAL*8 ZZ, T1
T1 = ZZ + 1.0D0
MYFUNC = T1
RETURN
END
用gfortran -c somefunction.f -o somefunction.o编译。
在 debug.c 文件中:
#include <stdio.h>
double cfunc(double x) {
double result = myfunc_( &x );
return result;
}
int main() {
double test = cfunc(3.0);
printf(" %.15f ",test);
}
用gcc -c debug.c -o debug.o编译。
然后我给gcc debug.o somefunction.o和./a.out。
但是,我得到的不是 3+1=4,而是无意义的数字。我该如何纠正这个问题?
P.S:如果解决了,我的实际功能有点复杂:
如果 MYFUNC 是类型
COMPLEX*16 FUNCTION MYFUNC(ZZ)而 ZZ 也是一个复数,我应该怎么做?如果 MYFUNC 调用了一些内置的 Fortran 函数,比如 CDLOG(ZZ) 会怎样?
如果它访问一个公共块怎么办?这也能容纳?
【问题讨论】:
-
你是否在C语言的任何地方声明了myfunc的返回类型?
-
你是对的,这就是问题所在。谢谢!任何其他点的提示也很感激!
-
@CraigEstey 不,不是。 Real*8 不是也从来没有成为标准 Fortran 的一部分,因此它的行为是由实现定义的,并且有一些编译器不支持它的问题。而是应该使用标准定义的种类机制。请参阅stackoverflow.com/questions/838310/fortran-90-kind-parameter 回答这个问题的最佳方法是 Fortran 标准定义的与 C 接口的方法。
-
@IanBush 我没有说这是一个标准,只是它已经存在了几十年。 fortran 是一种后沿语言。编写新代码的唯一原因是与遗留科学库(可能有数百万行代码使用
real*8)进行交互。real*8的使用早于kind至少两个十年。因此,每个需要相关的可靠的 fortran 编译器都将支持real*8。而且,real*8 xs比REAL(KIND=8) :: XS更紧凑,因此它之所以获胜,是因为它在任何地方都需要/使用的东西很简洁。而且,F2008 允许REAL64,这仍然更好。 -
您已经使用 fortran77 进行了标记,但如果可以选择在 fortran 端编写包装器,我强烈建议使用 FORTRAN2003 提供的
iso_c_binding模块:a) 它定义了以下数据类型保证与它们的 C 对应项匹配(= 不猜测real*8是否真的是double等),并且 b)bind(c, name="foo")函数在 C 中具有明确定义的签名和符号名称(保证foo(...)按预期工作)。简而言之,它会将您带出泥泞的实现定义的行为领域,进入符合标准的 C/fortran 定义明确的领域。