1

我想知道在现代 Fortran 中是否可以使用它自己或它的一部分来分配一个可分配的数组来做到这一点。这是一个简单的例子:

module modu
implicit none

type :: t
  integer :: i
end type

contains

subroutine assign(a,b)
type(t), allocatable, intent(out) :: a(:) 
type(t),              intent(in)  :: b
allocate(a(1))
a(1) = b
end subroutine
end module

!----------------------

program test
use modu
implicit none
type(t), allocatable :: a(:)

allocate(a(1))
a(1)%i = 2
call assign(a, a(1))
print*, a(1)%i
end program

此代码使用 ifort 18 给出正确答案,并使用 gfortran 7.4 返回“分段错误”。

注意:最初的问题有点复杂,因为call assign(a, a(1))应该用call assign(a, a(1)+b)operator + 正确重载来代替,但结论(尊重 ifort 和 gfortran)是相同的。

注意:在 fortran 重载赋值中的自赋值线程检查中,@IanH 区分了call assign(a,a)和, call assign(a,(a))但我相信它不能解决这个问题,因为我有可分配的参数。

注意:在 Fortran 分配时的线程自动数组分配中,@francescalus 解释了内在分配的自动分配,但我再次相信它不适用于这里。

4

2 回答 2

4

这个电话

call assign(a, a(1))

Fortran 的别名规则禁止使用。您在不同的参数中传递相同的值,但两者都不是pointer,或者target您正在修改其中一个。

然后,编译器取消分配a,因为它是intent(out). 这意味着旧的a(1)不再存在。但b仍然指向那里。a然后你在其他地方分配一个新的。然后你尝试b使用

a(1) = b

这肯定会失败,因为它指向一些未定义的内存。您对 Intel Fortran 很幸运,但您的代码是非法的。也许 Intell 将新的分配a到旧的地方a,但这纯粹是运气。

如果你这样做,它会起作用

type(t), allocatable, intent(inout) :: a(:) 
type(t),              value  :: b
deallocate(a)
allocate(a(1))
a(1) = b

我不确定,为什么它与intent(out)and崩溃value。这可能是编译器的问题,报告为错误 92178

于 2019-10-22T13:40:31.010 回答
3

可以使用同一数组的数组元素分配给可分配数组。例如,对于a可分配

a = [a(2), a(1)]

是有效的并且有预期的结果。无论a是内在类型(对于内在赋值)还是派生类型(对于内在或定义的赋值),这都是相同的。在左侧受到影响之前,右侧被视为完全评估为表达式。

但是,使用call assign(a,a(1))与此分配不同。

您引用的 IanH 回答中的要点与此处相关。定义的分配就像call assign(a,(a(1)))而不是call assign(a,a(1)).

这很重要,因为 Vladimir F 的回答中提到了别名限制,我不会重复。Usingcall assign(a,(a(1)))删除了别名,因为(a(1))它是一个表达式,其值是数组元素的值,而不是数组元素本身的值。这类似于valueVladimir F 提到的属性,但没有创建可定义的实体。

定义的赋值(rhs)精确地使用构造来避免这种别名问题。

关于您的 gfortran 结果,IanH为 GCC 创建了一个错误报告以回应其他问题。这可能与解释您在这里的惊喜有关。

于 2019-10-22T14:13:31.690 回答