2

我正在为一些 MPI 分散/收集例程使用一些现代 Fortran 包装器。我试图有一个包装器接口,它在输入上只有一个数组,并在输出上返回 MPI 操作的结果,对于几个派生类型,执行如下操作:

type(mytype), allocatable :: chunk(:),whole(:)

! [...] chunk descends from previous parts of the code

! Get global array
whole = gatherv(array=chunk,receiver_node=cpuid)

我正在使用返回allocatable数组的函数来执行此操作。gcc 6.2.0但是,gcc 7.1.0每当我返回未分配的结果时,我都会遇到分段错误。

我需要未分配结果的原因是有时我只需要在指定的 CPU 上收集整个数组,所以我不想在所有其他节点上浪费内存:接收节点返回一个带有数据的已分配数组,并且所有其他节点都会收到一个空且已释放的数组。

这是重现该问题的示例代码:

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)

你们以前有过同样的问题吗?或者,我是否违反了标准中的任何内容?我不明白为什么应该强制返回可分配数组的函数分配返回值。intent(out)这和在子程序中有一个虚拟变量不一样吗?

4

2 回答 2

3

函数结果与具有intent(out)属性的虚拟参数不同。此处的显着不同之处在于,必须始终在函数执行终止时定义非指针函数结果。Fortran 2008 12.6.2.2 p4 涵盖了这一点。

有必要但还不够,要分配的可分配函数结果(任何对象)被定义。

在某种程度上,您可以以始终引用函数结果的方式来考虑这一点(否则该函数将不会被执行)。未定义的实际参数也可能不会被引用,但这种引用不会是“自动的”。

正如评论中提到的,函数结果可能被分配为一个大小为零的数组。零大小的数组总是具有定义的值。

您可以在另一个问题中看到零大小数组和未分配数组的一些比较。

于 2018-01-08T18:15:01.440 回答
0

我怀疑主程序中的任何可分配数组都包含全局数据。我通常将这些变量放在一个模块中。这样,这个变量就不需要被传递,并且可以在主程序、子程序和/或函数中分配和释放。

由于数组是唯一的返回值,因此我将其更改为子例程。这对你有什么作用?PS '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
于 2018-01-26T19:06:28.680 回答