从C语言调用FORTRAN子程序

19

我正在尝试从C语言中调用FORTRAN函数。

我的问题是:

  1. 如果我的Fortran子程序的名称是fortRoutine,那么我应该如何在C语言中调用它?答案是使用fortRoutine_来调用。如果fortRoutine只包含一个字符数组参数,我可以这样传递吗:

    fortRoutine_("I am in fortran");
    
  2. 在调用FORTRAN子程序时,何时应使用按值传递以及何时应使用按引用传递?

由于我对C语言不熟悉,因此不清楚这个问题。如果可能的话,请提供一些好的教程链接。


1
提供更多信息,如平台/编译器,因为您所询问的问题高度依赖于平台。 - AndersK
3个回答

30
现在实现这一点的方式是在Fortran端使用Fortran ISO C绑定。 这是Fortran 2003语言标准的一部分,并且可用于许多编译器;它不特定于gcc。 在本站的许多答案中已经对其进行了描述。 作为语言标准的一部分,它与编译器和平台无关。 而且,您不需要了解编译器的内部传递约定。 使用ISO C绑定,在声明Fortran子例程或函数时,会导致Fortran编译器使用C调用约定,以便可以直接从C调用该过程。 您不需要添加隐藏参数或对Fortran子例程名称进行名称修饰,即没有下划线。 链接器使用的名称来自“bind”选项。
字符串是一个困难的情况,因为在C中它们在技术上是字符数组,您必须在Fortran中匹配这个。 您还必须处理字符串的不同定义:C以null结尾,Fortran以固定长度填充空格。 示例显示了如何实现这一点。 数字更容易处理。 唯一的问题是数组,因为C是行主要的,而Fortran是列主要的,所以多维数组被转置。
int main ( void ) {

   char test [10] = "abcd";

   myfortsub (test);

   return 0;

}

subroutine myfortsub ( input_string ) bind ( C, name="myfortsub" )

   use iso_c_binding, only: C_CHAR, c_null_char
   implicit none

   character (kind=c_char, len=1), dimension (10), intent (in) :: input_string
   character (len=10) :: regular_string
   integer :: i

   regular_string = " "
   loop_string: do i=1, 10
      if ( input_string (i) == c_null_char ) then
         exit loop_string
      else
         regular_string (i:i) = input_string (i)
      end if
   end do loop_string

   write (*, *) ">", trim (regular_string), "<", len_trim (regular_string)

   return

end subroutine myfortsub

您需要将 C 代码编译为目标文件,然后使用 gfortran 编译 Fortran 代码并将两者链接在一起:

gcc-mp-4.6   \
         -c  \
         test_fortsub.c

gfortran-mp-4.6   \
     test_fortsub.o  \
     myfortsub.f90  \
     -o test_fortsub.exe

输出结果为:

 >abcd<           4

2
通常这是最好的方法,但我认为,很多时候,如果一个C程序员询问,他们实际上并不想深入研究他们遗留的FORTRAN 77和更早期的代码。这时候用C编写一个包装器有时会更好。 - Vladimir F Героям слава
或者更糟的是,没有“iso_c_binding”的奢侈条件。不过,如果您控制两者,那么这是要采取的方法(尽管我通常选择在C端处理字符串内容,因为个人认为这样更简单)。 - user7116

3
当然,这完全取决于你所使用的FORTRAN编译器,但一般来说:
  1. No, you'll need to pass a hidden length argument for your string. Some compilers interleave these with the other parameters, directly after the string. Others, group all string length arguments at the end of the argument list.

    char str[11] = {0};
    fortranFunc_(str, sizeof(str) - 1);
    // remember that 'str' will need to be null terminated
    // and will be padding with spaces to fit the length
    // so for C passing strings to Fortran specify the length
    // less 1 so you can add a nul terminator, and on all strings
    // being filled in by FORTRAN, trim-end all spaces.
    
  2. Almost always it is pass by reference, but you can toggle this behavior using attributes on the dummy arguments on the FORTRAN side.

    int value = 10;
    fortranFunc_(&value);
    // INTEGER I
    
以下是与不同编译器相关的一些参考文献: 请注意,以上内容适用于各种编译器。

1

答案取决于编译器和系统(技术上,它的ABI)。对于GCC(它是C、C++、Ada和Fortran编译器),请阅读fortran mixed programming章节。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接