Fortran 函数返回未分配的数组导致分段错误
Fortran function returning unallocated array causes segmentation fault
我正在为某些 MPI scatter/gather 例程使用一些现代 Fortran 包装器而苦苦挣扎。我试图有一个包装器接口,它只有一个输入数组和 returns 输出的 MPI 操作结果,对于几种派生类型,做这样的事情:
type(mytype), allocatable :: chunk(:),whole(:)
! [...] chunk descends from previous parts of the code
! Get global array
whole = gatherv(array=chunk,receiver_node=cpuid)
我正在使用 return allocatable
数组的函数来执行此操作。但是,每当我 return 一个未分配的结果时,我都会在 gcc 6.2.0
和 gcc 7.1.0
上遇到分段错误。
我需要非分配结果的原因是有时我只需要在指定的 CPU 上收集整个数组,所以我不想在所有其他节点上浪费内存:接收器节点 return 是一个包含数据的已分配数组,所有其他节点接收一个空的且已解除分配的数组。
这是重现问题的示例代码:
program test_allocatable_fun
implicit none
integer, allocatable :: my_array(:)
integer :: n
n = 3; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n =-3; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 5; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 0; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
return
contains
function unallocated_array(n) result(array)
integer, intent(in) :: n
integer, allocatable :: array(:)
integer :: j
if (n>0) then
allocate(array(n))
array(:) = [(j,j=1,n)]
else
if (allocated(array)) deallocate(array)
end if
end function unallocated_array
end program test_allocatable_fun
分段错误发生在赋值行,即:
my_array = unallocated_array(n)
你们以前有过同样的问题吗?或者,我是否违反了标准中的任何内容?我不明白为什么 returning 一个可分配数组的函数应该被强制分配 return 值。这与子程序中有一个 intent(out)
虚拟变量不一样吗?
函数结果与具有 intent(out)
属性的伪参数不同。它在这里有一个显着的不同之处在于,当函数执行终止时,必须始终定义非指针函数结果。 Fortran 2008 12.6.2.2 p4 涵盖了这一点。
对于要分配的可分配函数结果(任何对象)进行定义是必要的,但还不够。
在某种程度上,您可以以始终引用函数结果的方式来考虑这一点(否则函数将不会被执行)。未定义的实际参数也可能不会被引用,但这样的引用不会是 "automatic".
如评论中所述,函数结果可能被分配为大小为零的数组。大小为零的数组始终具有定义的值。
您可以在 .
中看到一些零大小数组和未分配数组的比较
我怀疑主程序中的任何可分配数组都包含全局性质的数据。我通常把这样的变量放在一个模块中。这样这个变量不需要传递,可以在主程序、子程序、and/or 函数中分配和释放。
因为数组是唯一的return值,所以我把它改成了一个子程序。这对你有用吗? P.S。 'implicit none' 应该在每个模块、程序、函数和子例程中。
module fun
implicit none
integer, allocatable :: my_array(:)
end module fun
program test_allocatable_fun
use fun
implicit none
integer :: n
n = 3; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n =-3; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 5; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 0; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
return
contains
subroutine unallocated_array(n)
use fun
implicit none
integer, intent(in) :: n
integer :: j
if (n>0) then
allocate(my_array(n))
my_array(:) = [(j,j=1,n)]
else
if (allocated(my_array)) deallocate(my_array)
end if
end subroutine unallocated_array
end program test_allocatable_fun
我正在为某些 MPI scatter/gather 例程使用一些现代 Fortran 包装器而苦苦挣扎。我试图有一个包装器接口,它只有一个输入数组和 returns 输出的 MPI 操作结果,对于几种派生类型,做这样的事情:
type(mytype), allocatable :: chunk(:),whole(:)
! [...] chunk descends from previous parts of the code
! Get global array
whole = gatherv(array=chunk,receiver_node=cpuid)
我正在使用 return allocatable
数组的函数来执行此操作。但是,每当我 return 一个未分配的结果时,我都会在 gcc 6.2.0
和 gcc 7.1.0
上遇到分段错误。
我需要非分配结果的原因是有时我只需要在指定的 CPU 上收集整个数组,所以我不想在所有其他节点上浪费内存:接收器节点 return 是一个包含数据的已分配数组,所有其他节点接收一个空的且已解除分配的数组。
这是重现问题的示例代码:
program test_allocatable_fun
implicit none
integer, allocatable :: my_array(:)
integer :: n
n = 3; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n =-3; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 5; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 0; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
return
contains
function unallocated_array(n) result(array)
integer, intent(in) :: n
integer, allocatable :: array(:)
integer :: j
if (n>0) then
allocate(array(n))
array(:) = [(j,j=1,n)]
else
if (allocated(array)) deallocate(array)
end if
end function unallocated_array
end program test_allocatable_fun
分段错误发生在赋值行,即:
my_array = unallocated_array(n)
你们以前有过同样的问题吗?或者,我是否违反了标准中的任何内容?我不明白为什么 returning 一个可分配数组的函数应该被强制分配 return 值。这与子程序中有一个 intent(out)
虚拟变量不一样吗?
函数结果与具有 intent(out)
属性的伪参数不同。它在这里有一个显着的不同之处在于,当函数执行终止时,必须始终定义非指针函数结果。 Fortran 2008 12.6.2.2 p4 涵盖了这一点。
对于要分配的可分配函数结果(任何对象)进行定义是必要的,但还不够。
在某种程度上,您可以以始终引用函数结果的方式来考虑这一点(否则函数将不会被执行)。未定义的实际参数也可能不会被引用,但这样的引用不会是 "automatic".
如评论中所述,函数结果可能被分配为大小为零的数组。大小为零的数组始终具有定义的值。
您可以在
我怀疑主程序中的任何可分配数组都包含全局性质的数据。我通常把这样的变量放在一个模块中。这样这个变量不需要传递,可以在主程序、子程序、and/or 函数中分配和释放。
因为数组是唯一的return值,所以我把它改成了一个子程序。这对你有用吗? P.S。 'implicit none' 应该在每个模块、程序、函数和子例程中。
module fun
implicit none
integer, allocatable :: my_array(:)
end module fun
program test_allocatable_fun
use fun
implicit none
integer :: n
n = 3; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n =-3; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 5; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
n = 0; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
return
contains
subroutine unallocated_array(n)
use fun
implicit none
integer, intent(in) :: n
integer :: j
if (n>0) then
allocate(my_array(n))
my_array(:) = [(j,j=1,n)]
else
if (allocated(my_array)) deallocate(my_array)
end if
end subroutine unallocated_array
end program test_allocatable_fun