Fortran接口调用返回指针的C函数

时间:2010-10-04 04:15:16

标签: c fortran cuda gpu interop

我有一个C函数,

double* foofunc() 
{
  /* Function Body */
}

我不知道如何在Fortran中声明一个接口来调用此C函数。

此外,如果指针应指向GPU device memory,我如何在Fortran界面中定义?我是否需要使用DEVICE属性。

请使用Fortran支持的功能,直到2003年。

有什么建议吗?

4 个答案:

答案 0 :(得分:3)

由于您拥有Fortran 2003,因此连接Fortran和C的简便方法是使用ISO C Binding。 (大多数Fortran 95编译器现在都支持ISO C绑定,即使它们不是完整的Fortran 2003编译器。)这远远好于早期答案中提出的复杂方法,这在早期的时代是必要的 - 它是语言的一部分,因此是可移植的,与编译器和平台无关。但Fortran 2003版本并没有涵盖任何可能性。 (下一个Fortran将添加与C接口的其他情况。)您可以轻松传递一个C指针的参数 - 只需在Fortran声明中省略“value”atttribute。指向指针的指针需要C_PTR。我不知道指针作为一个函数返回...我必须在有时间时进行实验。如果必须,请创建一个简单的C glue例程,将函数返回的指针转换为参数 - 这种情况很容易。

指向GPU设备内存的指针 - 除非您的编译器具有非标准功能,否则它将不具有“DEVICE”。也许“波动”会有所帮助吗?创建适当的用户定义类型......

gfortran手册中的“与C的互操作性”中有一些例子。由于这是该语言的一部分,即使您不使用gfortran,此文档也应该有所帮助。

答案 1 :(得分:1)

正如M. S. B.所说,使用fortran 2003 C互操作性功能是最简单的 只需将函数结果声明为type(c_ptr),并通过调用c_f_pointer将其转换为fortran指针。

以下简单示例在编译时使用:
gfortran foo.f03 foofunc.c -o foo.exe
(gfortran版本4.5.0)

foo.f03的内容:

program foo
  use, intrinsic :: iso_c_binding, only : c_ptr,        &
                                          c_f_pointer,  &
                                          c_double
  implicit none
  type(c_ptr) :: c_p
  real(c_double), pointer :: f_p

  interface
    function foofunc() bind(c)
      import :: c_ptr
      implicit none
      type(c_ptr) :: foofunc
    end function foofunc
  end interface

  c_p = foofunc()
  call c_f_pointer(c_p, f_p)
  print *, f_p
end program foo

foofunc.c的内容:

double bar = 2;

double *foofunc()
{
  return &bar;
}
但是,我不知道它与指向GPU设备内存的指针有多好。从来没有处理过。

答案 2 :(得分:0)

您想从Fortran Program调用C函数。有很多方法。

一种方法是将C例程转换为fortran。如果您的C程序冗长,复杂且经过充分测试,那么对您来说可能并不是一件容易的选择。另一种方法是将fortran转换为C.可能存在类似的问题。

如果您无法解决上述问题,那么您必须面对以下问题。

在编程用语中,它被称为混合语言编程。

我不知道哪种语言和操作系统U正在使用。因此,我将在下面给出四种替代方法,而不是提供现成的解决方案。我已经使用了所有已实现的应用程序前两个是那些幸运拥有强大操作系统(现在是一种稀有商品)的人。该程序运行速度快,适合硬实时工作。最后两个适用于任何操作系统,但程序运行缓慢,特别是在频繁调用C例程的情况下。您还必须在所有方法中进行更多的编程工作。还要注意你的C函数在每个替代方法中返回一个指针。

  1. 有些fortran编译器(不是全部)允许调用非fortran函数。这需要操作系统中运行fortran和C的适当设施。在这种情况下,在过程调用期间使用相同的堆栈管理。请仔细阅读两种语言和代码的程序员手册。

  2. 如果这不可能,那么你可以欺骗操作系统这样做但你需要用汇编程序编写的中间函数。您从fortran调用汇编程序例程,然后从汇编程序调用C例程并以相反的方式返回。您需要了解Fortran,Assembler和C三者的堆栈管理细节,并编写用于将fortran堆栈转换为C堆栈的代码。这将在汇编程序中。

  3. 在上述两种方法中,您必须了解您的链接器(或活页夹)的工作原理,您可能需要在那里做一些额外的工作。在任何一种情况下,它都是相同的.exe文件,因此您的程序将快速运行。在这种操作系统中,任何语言,彼此都很奇怪,可以混合使用。甚至可以使用DLL。如果运行时库使用与C函数具有相同名称但执行不同作业的fortran函数,则只会出现复杂性。支持混合语言编程的操作系统通常会为您提供一些防止这种情况的工具。

    1. 如果上述替代方案不可行,则将fortran和C程序作为单独的.exe运行,并作为两个并发进程运行。 (注意它们甚至可以在不同操作系统下的同一台计算机或不同的计算机上!)。现在,无论何时需要从fortran调用C,都可以通过任何可用的进程间通信机制传递所有参数和数据,比如管道,套接字或其他任何内容。 C程序可以通过类似的机制返回数据。一定要添加适当的代码来处理通过进程间通信传递的参数。同步两个进程并区分旧数据和最近的数据也是你的工作。不需要堆栈管理。

    2. 这个适合那些不喜欢堆栈,同步,链接器或任何需要智能的东西。如果必须经常调用C程序,程序将运行得最慢。反直觉地,如果C程序只需要调用一次,那么这也是最智能的解决方案!将数据从fortran程序输出到磁盘(平面文件或数据库)。然后调用C程序从同一文件读取并以相同的方式将数据返回到fortran。在更改语言之前要小心关闭文件。处理文件输入 - 输出调用中的所有错误。否则你会崩溃。

答案 3 :(得分:0)

您的答案与我的答案中的第1点相同(1.有些Fortran编译器......)。然而,您提到“但Fortran 2003版本并未涵盖所有可能性”。 这是一个实用的观点

程序员经常达到目标;即使最新版本的编译器或连接器不可用,也可能出现问题。我已经给出了现场测试的替代品学生有一种选择,另一种是“实时”问题。这可能需要更长的时间,但是如果你得到一个与另一种语言完美接口的Fortran版本,该怎么做。

如果您现有的调试fortran和C程序一起长达30,000行,那么在2000客户端系统中使用新版本的编译器可能会解除许多其他问题。人们已经失去了更多时间来处理这些问题,而不是花费额外的工作时间来使用现有编译器和操作系统中的常用资源自己编写一些连接器。我们在对应用程序的所有组件进行全新测试后实现新的编译器。黄金法则是“使用已知错误处理现有编译器比使用其最新版本具有未知错误更容易”。该规则仅适用于大型实际问题。