我有以下代码:
program testdatatype
integer(8), parameter :: Stot= 2
integer(8), dimension(Stot) :: Nf
integer(8) :: f, s, Qind
integer(8), dimension(:, :), allocatable :: NqG
real(16), dimension(:, :, :), allocatable :: d3xnormfac
type NqGtype
integer(8), dimension(:, :), allocatable :: NqGvalT
end type NqGtype
type(NqGtype), dimension(Stot) :: NqGT
type d3xnormfactype
real(16), dimension(:, :, :), allocatable :: d3xnormfacvalT
end type d3xnormfactype
type(d3xnormfactype), dimension(Stot) :: d3xnormfacT
! ----------------------------------------------------
! LOOP 1.1:
do s= 1, Stot, 1
Nf(s)= 2d0
write(*, *) 'NfLoop1.1= ', Nf(s)
end do
! LOOP 1.2:
do s= 1, Stot, 1
write(*, *) 'NfLoop1.2= ', Nf(s)
end do
! ----------------------------------------------------
! LOOP 2.1:
do s= 1, Stot, 1
allocate(NqG(Nf(s), Stot))
do f= 1, Nf(s), 1
NqG(f, s)= 5d0
NqGT(s)%NqGvalT= NqG
write(*, *) 'NqGLoop2.1= ', NqG(f, s)
write(*, *) 'NqGTLoop2.1= ', NqGT(s)%NqGvalT(f, s)
end do
deallocate(NqG)
end do
! LOOP 2.2:
do s= 1, Stot, 1
do f= 1, Nf(s), 1
write(*, *) 'NqGTLoop2.2= ', NqGT(s)%NqGvalT(f, s)
end do
end do
! ----------------------------------------------------
! LOOP 3.1:
do s= 1, Stot, 1
do f= 1, Nf(s), 1
allocate(d3xnormfac(Nf(s), Stot, NqGT(s)%NqGvalT(f, s)))
do Qind= 1, NqGT(s)%NqGvalT(f, s)
d3xnormfac(f, s, Qind)= 153d12
d3xnormfacT(s)%d3xnormfacvalT= d3xnormfac
write(*, *) 'd3xnormfacLoop3.1= ', d3xnormfac(f, s, Qind)
write(*, *) 'd3xnormfacTLoop3.1= ', d3xnormfacT(s)%d3xnormfacvalT(f, s, Qind)
end do
deallocate(d3xnormfac)
end do
end do
! LOOP 3.2:
do s= 1, Stot, 1
do f= 1, Nf(s), 1
do Qind= 1, NqGT(s)%NqGvalT(f, s)
write(*, *) 'd3xnormfacTLoop3.2= ', d3xnormfacT(s)%d3xnormfacvalT(f, s, Qind)
end do
end do
end do
! ----------------------------------------------------
end program testdatatype
我正在 mpif90 编译器上编译这个 .f90 文件。正如您所看到的,当我运行此代码时,很明显循环 1.1 中的 write
语句给出的值与循环 1.2 中的相同,即 Nf(:)
的值code> 对于循环 1.1 之外的所有 s 值都是正确的。这对于循环 2.1 和循环 2.2 是相同的(这次创建派生数据类型)。循环 1 的输出如下:
NfLoop1.1= 2
NfLoop1.1= 2
NfLoop1.2= 2
NfLoop1.2= 2
对于循环之外的任何 f 和 s 值(在循环 2.2 中),我能够调出数据类型 NqGT(s)%NqGT(f, s)
的任何正确值,其中它被创建了(循环2.1)。目前为止没有问题。当我使用循环 2 运行循环 1 变量时,给出以下输出:
NfLoop1.1= 2
NfLoop1.1= 2
NfLoop1.2= 2
NfLoop1.2= 2
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGTLoop2.2= 5
NqGTLoop2.2= 5
NqGTLoop2.2= 5
NqGTLoop2.2= 5
此外,当将循环 1 变量运行到循环 2 派生数据类型(进而与循环 3 一起使用)时,会给出以下输出:
NfLoop1.1= 2
NfLoop1.1= 2
NfLoop1.2= 2
NfLoop1.2= 2
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGLoop2.1= 5
NqGTLoop2.1= 5
NqGTLoop2.2= 5
NqGTLoop2.2= 5
NqGTLoop2.2= 5
NqGTLoop2.2= 5
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.1= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= -1.83360386755485123703987599430319601E-2466
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 0.00000000000000000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
d3xnormfacTLoop3.2= 153000000000000.000000000000000000000
但是,当我尝试对 Loop 3.1 执行相同操作时,我无法再获取派生数据类型的所有正确值d3xnormfacT(s)%d3xnormfacvalT(f, s, Qind)
,即循环 3.2 中打印的数据类型与循环 3.1 中相同数据类型打印的值不相等(某些值正确,但其他值不正确)。我怎样才能解决这个问题?我一定错过了一些东西(指针和/或派生数据类型的分配?)
最佳答案
在循环 3.1 中,您仅设置特定索引 d3xnormfac
但然后分配整个 d3xnormfac
数组到d3xnormfacT(s)%d3xnormfacvalT
。因为d3xnormfac
被释放然后分配多次,之前分配的值不保证仍然被设置。
由于您的特定循环顺序,d3xnormfac(:,1,:)
中的值未初始化。取决于编译器是否重新分配 d3xnormfac
到同一个地方并且内存是否被清理,这些值最终可能是正确的。对于我的 Intel(使用 -assume realloc-lhs
以允许自动分配),大多数值都是正确的。对于我的 gfortran,大多数值都是不正确的,如您所见。该行为可能也取决于真实的类型,这解释了您的观察结果。
了解这一点的一个好方法是在分配后初始化每个值。修改代码以将其添加到循环 3.1 中:
allocate(d3xnormfac(Nf(s), Stot, NqGT(s)%NqGvalT(f, s)))
d3xnormfac = -1234 ! -- Added this line
do Qind= 1, NqGT(s)%NqGvalT(f, s)
产生以下结果:
mach5% ifort -assume realloc_lhs -check all -warn all -traceback -g main.f90 && ./a.out
NfIN= 2
NfIN= 2
NfOUT= 2
NfOUT= 2
NqGIN= 15
NqGTIN= 15
NqGIN= 15
NqGTIN= 15
NqGIN= 15
NqGTIN= 15
NqGIN= 15
NqGTIN= 15
NqGTOUT= 15
NqGTOUT= 15
NqGTOUT= 15
NqGTOUT= 15
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacIN= 153000000000000.000000000000000000
d3xnormfacTIN= 153000000000000.000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= -1234.00000000000000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
d3xnormfacTOUT= 153000000000000.000000000000000000
您可以看到仍设置为 -1234 的部分。
澄清后
我现在发现这个问题来自于对可分配数组如何属于派生类型的误解。
d3xnormfacT(s)%d3xnormfacvalT
是它自己的可分配数组。它的排名为 3,并且(在分配之前)未分配。它(通常)使用常规分配语句进行分配,例如:
allocate(d3xnormfacT(s)%d3xnormfacvalT((Nf(s), Stot, NqGT(s)%NqGvalT(f, s)))
你没有这样做。您(无意中)使用 Fortran 的高级功能绕过了传统分配:自动左侧 (lhs) 分配。当为数组分配一个与其形状匹配的值时,该数组将被分配或重新分配以匹配。更多信息在这里:Automatic array allocation upon assignment in Fortran
您的声明:
d3xnormfacT(s)%d3xnormfacvalT= d3xnormfac
实际上是同时做两件事。第一,d3xnormfacT(s)%d3xnormfacvalT
正在分配以匹配 d3xnormfac
的大小,因为d3xnormfacT(s)%d3xnormfacvalT
与 d3xnormfac
的形状(3 维)匹配。二、新分配d3xnormfacT(s)%d3xnormfacvalT
被分配与 d3xnormfac
相同的值有。 (没有人指出其他任何事情。)
您应该更改代码以不使用此自动 lhs 分配。 2003 年标准允许这种自动 lhs 分配,但某些编译器(Intel 直到 2017 年)故意默认不支持它。我个人认为这是危险且不直观的,所以我通常会避免它。对于不了解此功能的开发人员来说,此功能可能是一个“陷阱”。防止这种情况发生的 gfortran (我猜你正在使用它,你只指定 mpif90
这只是一个包装器)标志是 -fno-realloc-lhs
.
一旦您更改了代码,您将更好地理解我的答案的其余部分,这就是您看到问题的真正原因。
编辑:正如 @eriktous 指出的那样,循环 2 中也存在同样的问题,但循环顺序意味着不会将未初始化的值放入输出中。我不太明白为什么s
索引派生数据类型和数组的最外层维度。也许是因为这只是一个玩具盒。如果您要扩展此代码,请务必解决这两个问题。
关于fortran - 在 Fortran 中多次循环后访问派生数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48508876/