2

我正在从 Fortran 90 程序调用 C 函数(我必须使用 Fortran 90)。这个 C 函数接受几个参数并返回一个浮点指针。我似乎无法在 Fortran 代码中正确打印返回的数据。它只是显示一个非常大的数字(我假设它是指针的地址。)

我已经成功地将 REAL Fortran 变量作为参数传递,让 C 函数设置它们(如 Fortran 通过引用传递)并随后访问数据。但是,我必须将指针作为返回变量返回,因为这是旧函数使用的方法(我正在重新实现。)

Fortran 90 中有没有办法从 C 函数返回的非字符(实数、整数等)指针访问数据?(请注意:我不能使用 ISO C 绑定,因为这仅适用于 Fortran 2003 及更高版本。)我已经在下面说明了我正在尝试做的事情......

谢谢!

Fortran 程序

program test_real
    real, dimension(10) :: realpt
    integer nbr
    integer i
    real :: a=1.0
    real :: b=2.0
    real :: c=3.0

    nbr = 9
    realpt = getpointer(a, b, c)

    do 10 i = 1, nbr
        print *,"return: ",realpt(i)
10  continue

stop
End

C 函数

float* getpointer(float *a, float *b, float *c) {
    float *rfl = (float *) calloc(9,sizeof(float));
    int i=0;

    for(i=0;i<3;i++) {
        rfl[i] = *a;
    }
    for(i=3;i<6;i++) {
        rfl[i] = *b;
    }
    for(i=6;i<9;i++) {
        rfl[i] = *c;
    }
    return(rfl);
}   // End of getpointer function

输出

return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
4

3 回答 3

4

此声明“我不能使用 ISO C 绑定,因为它仅适用于 Fortran 2003 及更高版本。” 很奇怪;当前任何支持 F90 的编译器也支持 F2003 的大部分或全部。

正如 Eric Urban 指出的那样,在 fortran 中进行数组分配当然是最简单的(实际上您可以使用数组切片或广播来更轻松地进行填充)。但是假设您需要调用一些采用这种形式的 C 例程,只需使用ISO_C_BINDING模块来实现 C 和 fortran 之间的可移植接口:

program test_real
    use, intrinsic :: iso_c_binding
    real(kind=c_float), pointer :: realpt(:)
    type(c_ptr) :: ptr
    integer :: nbr
    integer :: i
    real :: a=1.0
    real :: b=2.0
    real :: c=3.0

    interface
       function getpointer(a, b, c) result(ptr) bind(C,name="getpointer")
           use, intrinsic :: iso_c_binding
           implicit none
           type(c_ptr) :: ptr
           real(kind=c_float) :: a, b, c
        end function getpointer
      end interface

    nbr = 9
    ptr = getpointer(a, b, c)
    call c_f_pointer(ptr, realpt, [nbr])

    print *,"return: ",realpt
end

编译和运行给出

$ gcc -c fooc.c
$ gfortran -c foo.f90
$ gfortran -o foo foo.o fooc.o
$ ./foo
 return:    1.0000000       1.0000000       1.0000000       2.0000000       2.0000000       2.0000000       3.0000000       3.0000000       3.0000000

如果您尝试以某种方式执行此操作来绕过 7 年以上的编译器限制,那么有很多脆弱的不可移植的方法可以做到这一点,但这真的不值得心痛。

更新:如果您不能接触(甚至重新编译)一些较旧的 fortran,那么您至少可以为 C 程序制作一个 F2003 包装器并拥有较旧的 fortran 链接:

foowrapper.f90:

module wrapper

contains

subroutine wrapgetpointer(outarr)
    use, intrinsic :: iso_c_binding
    implicit none

    real, intent(out), dimension(:) :: outarr
    real(kind=c_float), pointer :: realpt(:)
    type(c_ptr) :: ptr
    integer :: nbr = 9
    real(kind=c_float) :: a, b, c

    interface
       function getpointer(a, b, c) result(ptr) bind(C,name="getpointer")
           use, intrinsic :: iso_c_binding
           implicit none
           type(c_ptr) :: ptr
           real(kind=c_float) :: a, b, c
        end function getpointer
      end interface

    a = 1.
    b = 2.
    c = 3.
    ptr = getpointer(a, b, c)
    call c_f_pointer(ptr, realpt, [nbr])

    outarr(1:nbr) = realpt
end subroutine wrapgetpointer

end module wrapper

foo.f90:

program test_real
    use wrapper

    real, dimension(9) :: array
    call wrapgetpointer(array)

    print *,"return: ",array
end

编译和运行:

$ gfortran -c foowrapper.f90
$ gfortran -c foo.f90
$ gcc -c fooc.c
$ gfortran -o foo foo.o foowrapper.o fooc.o
$ ./foo
 return:    1.0000000       1.0000000       1.0000000       2.0000000       2.0000000       2.0000000       3.0000000       3.0000000       3.0000000
于 2013-03-22T20:22:14.497 回答
1

在您的代码中设置隐式 none,您就会明白为什么没有得到您想要的结果。

Fortran 中的数组值函数通常通过传递一个“隐藏”参数来实现,该参数是函数应该写入其结果的内存地址。这与您的用例没有太多共同之处。

如果您坚持使用 Fortran 90,则无法做到这一点。您将需要使用某种扩展。

请注意,来自 F2003 的 C 互操作性是对 F90 的扩展...

(Cray 指针也是如此,但如果你必须使用扩展,我知道我会选择哪一个。)

于 2013-03-22T20:28:46.903 回答
0

我最终没有实施包装解决方案。对于无法使用 Fortran 2003 的情况,似乎对我有用的是 Cray 指针。我不确定这些在较新的编译器中的可行性,但对于我正在使用的 F90 编译器(英特尔 ifort 9.1),它工作得很好。

Cray 指针可以与返回的 C 指针一起使用。为了在 Fortran 中将 Cray 指针声明为浮点数组,例如:

real, dimension(10) :: realpt
pointer (ptemp,realpt) 
nbr = 9

然后你可以像这样调用C函数:

    ptemp = getpointer(a, b, c)    
    do 10 i = 1, nbr        
        print *,"return: ",realpt(i)
10  continue

这是一个解释如何使用 Cray 指针的资源:

http://gcc.gnu.org/onlinedocs/gfortran/Cray-pointers.html

于 2013-03-26T19:33:59.300 回答