非连续数组部分的来源分配
Sourced allocation of a non-contiguous array section
关于最近关于如何简洁地声明数组形状,我尝试了以下三种模式,即(A)自动重新分配,(B)源分配,和(C ) 具有假定形状的分配。然后 gfortran 似乎在源分配的情况下为 b(:,:)
给出了不正确的结果。在这里,我做错了什么,还是仅仅是因为它还没有得到 gfortran 的完全支持?虽然后者看起来很有可能,但我不太确定我对 gcc5 和 6 的安装或使用是否正确(我使用的是 Linux x86_64)。
program main
implicit none
integer, parameter :: p=3, q=4, r=5
integer a( p, q, r ), i, j, k
integer, allocatable :: b( :, : )
a = reshape( [ ((( 100*i + 10*j + k, i=1,p), j=1,q), k=1,r) ], [p,q,r] )
print *
print *, "shape( a ) = ", shape( a )
print *, "a(:,:,:) = ", a
print *, "a(:,1,:) = ", a(:,1,:)
b = a( :, 1, : ) !! (A) automatic (re)allocation
! allocate( b, source = a( :, 1, : ) ) !! (B) sourced allocation
! allocate( b, mold = a( :, 1, : ) ) !! (C) allocation with assumed shape
print *
print *, "shape( b ) = ", shape( b )
print *, "b(:,:) = ", b
end
结果:(在所有情况下,自动重新分配都会给出正确的结果。)
gfortran4.8.2
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B], [C]
f951: internal compiler error: Segmentation fault
gfortran5.2.1
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B], [C]
allocate( b, source = a( :, 1, : ) )
1
Error: Array specification required in ALLOCATE statement at (1)
gfortran6.0.0 (experimental)
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B] <--- seems incorrect
shape( b ) = 3 5
b(:,:) = 0 -1094645928 57 141 241 341 142 242 342 143 243 343 144 244 344
[C]
shape( b ) = 3 5
b(:,:) = (garbage data, reasonable)
Intel Fortran 14.0.1 (-assume realloc_lhs)
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[C]
shape( b ) = 3 5
b(:,:) = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Oracle Fortran 12.4
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[C]
shape( b ) = 3 5
b(:,:) = (garbage data, reasonable)
源分配在 Fortran 2003 中引入,rules/constraints 在 Fortran 2008 中更改。gfortran 5.2.1 拒绝该程序似乎是遵循 F2003 的结果。
在 F2003 下,源分配需要为要分配的数组明确指定数组边界。在 F2008 下,这不是必需的,另外可以指定要分配的多个对象。因此,您的代码无效 F2003。
不过,该程序(嗯,那个分配部分)是有效的 F2008:要分配的数组的边界可能来自源表达式,就像值一样。数组部分的连续性或其他方式不重要,因为表达式的值(和边界)是关键。自然地,表达式数组边界的计算提供了出错的机会。
综上所述,分配语句在F2008下有效,在F2003下无效。使用 F2003 规则的编译器必须能够检测到违规行为,而不是随意胡说八道。但是F2008很容易做bug。
而且,由于您的测试,为 gfortran 编写此代码的安全方法是
allocate(b(p,r), source=a(:,1,:))
确实,documentation for gfortran 将边界的给出列为 "unimplemented"。
关于最近b(:,:)
给出了不正确的结果。在这里,我做错了什么,还是仅仅是因为它还没有得到 gfortran 的完全支持?虽然后者看起来很有可能,但我不太确定我对 gcc5 和 6 的安装或使用是否正确(我使用的是 Linux x86_64)。
program main
implicit none
integer, parameter :: p=3, q=4, r=5
integer a( p, q, r ), i, j, k
integer, allocatable :: b( :, : )
a = reshape( [ ((( 100*i + 10*j + k, i=1,p), j=1,q), k=1,r) ], [p,q,r] )
print *
print *, "shape( a ) = ", shape( a )
print *, "a(:,:,:) = ", a
print *, "a(:,1,:) = ", a(:,1,:)
b = a( :, 1, : ) !! (A) automatic (re)allocation
! allocate( b, source = a( :, 1, : ) ) !! (B) sourced allocation
! allocate( b, mold = a( :, 1, : ) ) !! (C) allocation with assumed shape
print *
print *, "shape( b ) = ", shape( b )
print *, "b(:,:) = ", b
end
结果:(在所有情况下,自动重新分配都会给出正确的结果。)
gfortran4.8.2
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B], [C]
f951: internal compiler error: Segmentation fault
gfortran5.2.1
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B], [C]
allocate( b, source = a( :, 1, : ) )
1
Error: Array specification required in ALLOCATE statement at (1)
gfortran6.0.0 (experimental)
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B] <--- seems incorrect
shape( b ) = 3 5
b(:,:) = 0 -1094645928 57 141 241 341 142 242 342 143 243 343 144 244 344
[C]
shape( b ) = 3 5
b(:,:) = (garbage data, reasonable)
Intel Fortran 14.0.1 (-assume realloc_lhs)
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[C]
shape( b ) = 3 5
b(:,:) = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Oracle Fortran 12.4
[A]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[B]
shape( b ) = 3 5
b(:,:) = 111 211 311 112 212 312 113 213 313 114 214 314 115 215 315
[C]
shape( b ) = 3 5
b(:,:) = (garbage data, reasonable)
源分配在 Fortran 2003 中引入,rules/constraints 在 Fortran 2008 中更改。gfortran 5.2.1 拒绝该程序似乎是遵循 F2003 的结果。
在 F2003 下,源分配需要为要分配的数组明确指定数组边界。在 F2008 下,这不是必需的,另外可以指定要分配的多个对象。因此,您的代码无效 F2003。
不过,该程序(嗯,那个分配部分)是有效的 F2008:要分配的数组的边界可能来自源表达式,就像值一样。数组部分的连续性或其他方式不重要,因为表达式的值(和边界)是关键。自然地,表达式数组边界的计算提供了出错的机会。
综上所述,分配语句在F2008下有效,在F2003下无效。使用 F2003 规则的编译器必须能够检测到违规行为,而不是随意胡说八道。但是F2008很容易做bug。
而且,由于您的测试,为 gfortran 编写此代码的安全方法是
allocate(b(p,r), source=a(:,1,:))
确实,documentation for gfortran 将边界的给出列为 "unimplemented"。