【问题标题】:Calling FORTRAN function from C wrapper从 C 包装器调用 FORTRAN 函数
【发布时间】: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:如果解决了,我的实际功能有点复杂:

  1. 如果 MYFUNC 是类型 COMPLEX*16 FUNCTION MYFUNC(ZZ) 而 ZZ 也是一个复数,我应该怎么做?

  2. 如果 MYFUNC 调用了一些内置的 Fortran 函数,比如 CDLOG(ZZ) 会怎样?

  3. 如果它访问一个公共块怎么办?这也能容纳?

【问题讨论】:

  • 你是否在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 xsREAL(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 定义明确的领域。

标签: c fortran fortran77


【解决方案1】:

除了返回类型之外,您还需要注意 Fortran 过程名称被转换为您从 C 访问的符号的方式。没有标准,它完全取决于 Fortran 编译器和平台,所以您如果您想要可移植性,则必须使用一些配置时检测和宏。

例如,Fortran MYFUNC() 需要从 C 中调用为:

  • Windows 上 Intel Fortran 下的MYFUNC()
  • IBM XL Fortran 下的myfunc() (xlf)
  • myfunc_() 在大多数其他情况下(包括 Windows 上的 GNU Fortran)

(当 Fortran 例程在模块中时,情况会变得更加复杂,因为损坏的名称会以模块和_MOD__mp_ 等为前缀)

现代的 Fortran 解决方案是在 Fortran 端声明一个 bind(C) 例程,这会关闭此修改(或者您可以指定显式绑定名称)。

【讨论】:

    【解决方案2】:

    好吧,仅供参考,正如@IanBush所说,C程序应该已经声明了myfunc的返回类型,

    #include <stdio.h>
    
    double myfunc_(double*);
    
    double cfunc(double x) {
        double result = myfunc_( &x );
        return result;
    }
    int main() {
         double test = cfunc(3.0);
         printf(" %.15f ",test);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-25
      • 1970-01-01
      • 2012-12-17
      • 1970-01-01
      • 2021-07-14
      • 1970-01-01
      • 1970-01-01
      • 2016-01-01
      相关资源
      最近更新 更多