【问题标题】:Calling a FORTRAN subroutine from C从 C 调用 FORTRAN 子例程
【发布时间】:2012-01-02 17:26:33
【问题描述】:

我正在尝试从 C 调用 FORTRAN 函数

我的问题是:

  1. 如果 fortRoutine 是我的 fortran 子例程的名称,那么我从 C 调用它 作为fortRoutine_。如果fortRoutine 只包含一个字符数组参数,那么我可以这样传递:

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

由于我是 C 新手,所以我对此一无所知。如果可能的话,请推荐一些好的教程链接。

【问题讨论】:

  • 提供更多信息,例如平台/编译器,因为您的要求高度依赖于平台。

标签: c fortran fortran-iso-c-binding


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    当然,这一切都取决于您的 FORTRAN 编译器,但一般来说:

    1. 不,您需要为您的字符串传递一个隐藏的长度参数。一些编译器将这些与其他参数交错,直接在字符串之后。其他人,将所有字符串长度参数分组在参数列表的末尾。

      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. 几乎总是通过引用传递,但您可以使用 FORTRAN 端的虚拟参数上的属性来切换此行为。

      int value = 10;
      fortranFunc_(&value);
      // INTEGER I
      

    这里有一些参考,根据不同的编译器适用:

    【讨论】:

      【解决方案3】:

      现在的方法是在 Fortran 端使用 Fortran ISO C 绑定。这是 Fortran 2003 语言标准的一部分,可用于许多编译器;它不是特定于 gcc 的。该网站的许多答案中已对此进行了描述。作为语言标准的一部分,它独立于编译器和平台。而且您不需要了解编译器的内部传递约定。 ISO C 绑定在 Fortran 子例程或函数的声明中使用时,会导致 Fortran 编译器使用 C 调用约定,以便可以直接从 C 调用该过程。您无需添加隐藏参数或名称修改Fortran 子程序名称,即没有下划线。链接器使用的名称来自“绑定”选项。

      字符串是一个困难的情况,因为从技术上讲,它们在 C 中是字符数组,您必须在 Fortran 中匹配它。您还必须处理字符串的不同定义:C 以空结尾,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
      

      【讨论】:

      • 通常这是最失败的方式,但我认为,很多时候,如果 C 程序员要求,他们通常真的不想挖掘他们遗留的 FORTRAN 77 和更旧的代码。有时最好用 C 编写一个包装器。
      • 或者更糟糕的是,没有iso_c_binding 的奢侈。尽管如此,+1 如果您同时控制它,这是可以采用的方法(尽管我通常选择在 C 端管理字符串内容,更简单的恕我直言)。
      猜你喜欢
      • 2014-01-14
      • 1970-01-01
      • 2019-07-08
      • 2016-10-13
      • 2016-03-09
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多