非连续数组部分的来源分配

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"。