将函数名作为参数传递时,函数不将数组作为输入

When passing function name as argument, the function does not take array as input

我正在编写一个可以将函数名称作为参数的子例程。 在我的示例中,它是 call call_test(ga),其中 ga 是一个函数 ga(x).

如果 x 是标量,我的旧做法就可以正常工作。 问题是如果 x 是一个数组,程序就会失败。

可以重现问题的最小样本是下面的代码:


module fun

    implicit none
    private
    public    ::  ga, call_test

     contains

     subroutine call_test(fn)
        double precision,external::fn
        double precision::f
        double precision,dimension(0:2)::x0


        x0 = 0.111d0
        print*,'Input x0=',x0
        print*,'sze x0:',size(x0)


        f = fn(x0)
        print*,'fn(x0)=',f

    end subroutine call_test


     function ga(x) result(f)
        double precision,dimension(0:)  :: x
        double precision::f

        print*,'size x inside ga:',size(x)
        print*,'x in ga is:=',x

        f = sum(x)
     end function ga

end module


program main
    use fun

    call call_test(ga)

end program main

使用最新的ifort,我的执行结果是:

 Input x0=  0.111000000000000       0.111000000000000       0.111000000000000     
 sze x0:                     3
 size x inside ga:       140732712329264
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image              PC                Routine            Line        Source             
a.out              000000010C6EC584  Unknown               Unknown  Unknown
libsystem_platfor  00007FFF20610D7D  Unknown               Unknown  Unknown
a.out              000000010C6C62B2  _MAIN__                    32  main.f90
a.out              000000010C6C5FEE  Unknown               Unknown  Unknown

使用gfortran结果是

 Input x0=  0.11100000000000000       0.11100000000000000       0.11100000000000000     
 sze x0:           3
 size x inside ga:           0
 x in ga is:=
 fn(x0)=   0.0000000000000000

我的问题是为什么会这样,以及如何让它发挥作用。非常感谢基于我的代码的功能代码解决方案。

@IanBush 在他的评论中是正确的。您需要一个显式接口,因为函数参数采用假定形状的虚拟参数。由于您的代码中还有其他一些已弃用的功能,这里是它的现代重新实现,希望能改进 Fortran 社区编码实践,


module fun

    use iso_fortran_env, only: RK => real64
    implicit none
    private
    public    ::  ga, call_test

    abstract interface
        function fn_proc(x) result(f)
            import RK
            real(RK), intent(in) :: x(0:)
            real(RK) :: f
        end function fn_proc
    end interface

contains

    subroutine call_test(fn)

        implicit none
        procedure(fn_proc) :: fn
        real(RK) :: f
        real(RK) :: x0(0:2)

        x0 = 0.111_RK
        write(*,"(*(g0,:,' '))") 'Input x0 =',x0
        write(*,"(*(g0,:,' '))") 'sze x0:',size(x0)
        f = fn(x0)
        write(*,"(*(g0,:,' '))") 'fn(x0) =', f

    end subroutine call_test

     function ga(x) result(f)
        real(RK), intent(in) :: x(0:)
        real(RK) :: f

        write(*,"(*(g0,:,' '))") 'size x inside ga:',size(x)
        write(*,"(*(g0,:,' '))") 'x in ga is:',x

        f = sum(x)
     end function ga

end module


program main
    use fun
    call call_test(ga)
end program main

注意 abstract interface 的用法。 import 语句仅导入符号 RK 以便在摘要中使用。没有它,您将不得不 use iso_fortran_envRK 声明为 real64。不要使用 double precision,它已被弃用,并不一定表示 64 位实数。另外,请注意 0.111d00.111_RK 的转换。另外,我强烈建议不要使用单字母变量名。它们丑陋、容易出错且没有提供信息。现代 Fortran 允许变量名最长为 63 个字符。使用长但具有描述性的变量名没有坏处。这是代码输出,

$main
Input x0 = 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 3
x in ga is: 0.11100000000000000 0.11100000000000000 0.11100000000000000
fn(x0) = 0.33300000000000002