将函数名作为参数传递时,函数不将数组作为输入
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_env
将 RK
声明为 real64
。不要使用 double precision
,它已被弃用,并不一定表示 64 位实数。另外,请注意 0.111d0
到 0.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
我正在编写一个可以将函数名称作为参数的子例程。
在我的示例中,它是 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_env
将 RK
声明为 real64
。不要使用 double precision
,它已被弃用,并不一定表示 64 位实数。另外,请注意 0.111d0
到 0.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