Fortran 中的零大小数组到底发生了什么?

Dan*_*Sp. 5 arrays fortran memory-management

我见过几个关于将未分配的数组传递到函数或子例程的问题,这些问题会导致运行时错误,其中推荐的解决方案是在调用过程中以零长度分配它。我做了一些实验:

program test
   integer, allocatable :: A(:)

   allocate(A(3))
   print*, size(A)
   deallocate(A)

   allocate(A(-5:-3))
   print*, size(A)
   deallocate(A)

   allocate(A(0))
   A(0) = 9
   print*,A(0),'Size:',size(a)
   deallocate(a)

   allocate(A(-4))
   print*,size(A)
   deallocate(A)

   allocate(A(-4:-4))
   print*,size(A)
end  
Run Code Online (Sandbox Code Playgroud)

第一个很明显。一个长度为 3 的数组。第二个数组利用了 Fortran 的一个很酷的特性,定义了你自己的索引限制。它是一个长度为 3 的数组,包含元素 A(-5)、A(-4) 和 A(-3)。

第三个变得冒险。我用零分配它。我可以赋值!它打印: 9 尺寸: 0
第四个也打印尺寸为零!

显然,分配长度为 1 且索引为 -4 的数组的正确方法是最后一种。

问题:在第三个和第四个中,我是否只是写入了可能属于其他某个变量的内存(当然,这个示例没有其他变量除外)?

roy*_*vib 1

除此之外,代码无效,如果问题是“是否A(0)正在访问某些不应该访问的内存区域”,我想很可能是这样。虽然结果取决于编译器(并且不能证明任何事情),但我们可以使用 看到一些信息c_loc,例如,

program test
    use iso_c_binding, only: c_loc
    implicit none
    integer, target :: i
    integer, allocatable, target :: X(:), A(:), B(:)

    allocate( X( 1 ), A( 0 ), B( 1 ) )

    print *, "X:"
    do i = 0, 2
        print *, i, c_loc( X( i ) ), X( i )
    enddo

    print *, "A:"
    do i = 0, 2
        print *, i, c_loc( A( i ) ), A( i )
    enddo

    print *, "B:"
    do i = 0, 2
        print *, i, c_loc( B( i ) ), B( i )
    enddo
end  
Run Code Online (Sandbox Code Playgroud)

然后 gfortran-7.2 (没有选项)给出

 X:
           0      140362656006716           0
           1      140362656006720           0   <-- (*1)
           2      140362656006724 -1879048192
 A:
           0      140362656006732 -1879048192
           1      140362656006736           0
           2      140362656006740 -1879048192
 B:
           0      140362656006748 -1879048192
           1      140362656006752           0   <-- (*2)
           2      140362656006756 -1879048192
Run Code Online (Sandbox Code Playgroud)

Oracle Studio fortran 12.5(无选项)给出

 X:
 0 20258316 0
 1 20258320 0  <-- (*1)
 2 20258324 0
 A:
 0 20258348 0
 1 20258352 0
 2 20258356 0
 B:
 0 20258380 0
 1 20258384 0  <-- (*2)
 2 20258388 0
Run Code Online (Sandbox Code Playgroud)

其中允许我们(=用户)访问的有效内存区域仅为(*1)和(*2)。由于上面的数组元素是在内存上连续访问的,除了 (*1) 和 (*2) 之外的内存位置可能代表一些其他数据/元数据/缓冲区等,如果我们无意中修改了这些值(包括 WW3 或最近,大规模的数字货币盗窃......?)。众所周知,我们通常可以使用像这样的选项来检查这一点gfortran-7 -fcheck=all,它给出了

 X:
At line 11 of file test.f90
Fortran runtime error: Index '0' of dimension 1 of array 'x' below lower bound of 1
Run Code Online (Sandbox Code Playgroud)

f95 -C test.f90(对于 Oracle)

 X:
 ******  FORTRAN RUN-TIME SYSTEM  ******
Subscript out of range. Location:  line 11 column 31 of 'test.f90'
Subscript number 1 has value 0 in array 'X'
Run Code Online (Sandbox Code Playgroud)

我们遇到类似的错误A(0),因此不允许访问A(0)(仅仅因为A是一个空数组)。(例外情况是A通过参数或存储关联等访问时,但我想这是另一个故事了......)