在Fortran中分配时自动进行数组分配

Don*_*nna 11 memory arrays fortran gfortran

我们最近发现我们正在为Fortran中的未分配数组进行分配.GNU gfortran编译器没有捕获错误,代码在OSX和Linux下运行.但是,IBM Power PC上的代码分段错误相同.

我的问题是,以下代码是否正确?似乎分配给的数组array在某些体系结构上自动分配内存,但在其他体系结构上则不然.是否有实施具体细节在这里工作?

代码是混合的C/Fortran代码:

#include <stdlib.h>

void assign_array_(double x[], int* n);
void print_array_();

int main()
{
    int n,i;
    double *x;

    n = 5;
    x = (double*) malloc(sizeof(double)*n);

    for (i = 0; i < n; i++)
        x[i] = (double) i;

    assign_array_(x,&n);
    print_array_();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

和Fortran代码:

MODULE test_mod
  DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:) :: array
  integer :: nsize
END MODULE test_mod

SUBROUTINE assign_array(x,n)
  USE test_mod
  IMPLICIT NONE

  INTEGER :: n
  DOUBLE PRECISION :: x(n)

  CALL test_allocated()
  array = x
  CALL test_allocated()
  nsize = n

END SUBROUTINE assign_array


SUBROUTINE print_array()
  USE test_mod, ONLY: nsize, array
  IMPLICIT NONE

  INTEGER :: i

  DO i = 1,nsize
     WRITE(6,'(F24.16)') array(i)
  END DO

END SUBROUTINE print_array

SUBROUTINE test_allocated()
  USE test_mod
  IMPLICIT NONE

  IF (ALLOCATED(array)) THEN
     WRITE(6,*) 'Array is allocated'
     WRITE(6,*) 'size is ', SIZE(array)
  ELSE
     WRITE(6,*) 'Array is NOT allocated'
  END IF
END SUBROUTINE test_allocated
Run Code Online (Sandbox Code Playgroud)

输出(运行时)是:

Array is NOT allocated
Array is allocated
size is            5
  0.0000000000000000
  1.0000000000000000
  2.0000000000000000
  3.0000000000000000
  4.0000000000000000
Run Code Online (Sandbox Code Playgroud)

这是Power PC上的输出:

Array is NOT allocated
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)

总结:它在GNU(GNU Fortran(MacPorts gcc5 5.4.0_0)5.4.0)gfortran在OSX(arch:x86_64h)和Linux(在OSX上托管的虚拟机,GNU Fortran(Ubuntu 4.9.4-)中编译时运行2ubuntu1~14.04.1)4.9.4),但在使用GNU Fortran(GCC)4.4.7 20120313(Red Hat 4.4.7-17)编译的Power PC(arch:ppc64)上编译时无法运行.在我们的原始代码中,Power PC实现仅在代码中稍后进行了分段,其中引用了分配数组的条目,使得我们的"错误"(如果它实际上是一个错误)真的难以追踪.

上述代码的正确行为是什么?

fra*_*lus 22

代码的有效性就像

integer, allocatable :: array(:)
array = (/1,2,3/)
end
Run Code Online (Sandbox Code Playgroud)

取决于用于解释它的Fortran标准.

Fortran 2003引入了内在赋值的自动分配概念.在Fortran 2003之前,必须分配这种赋值语句左侧的数组,并且形状与右侧的数组相同.

从Fortran 2003开始,只有排名需要匹配.如果存在形状不匹配,则首先释放阵列,然后重新分配到正确的形状.如果最初没有分配,它将被分配.

因此,上面的程序不是有效的Fortran 90,但是有效的Fortran 2003.

那么,真实世界代码的不同之处在于编译器支持的语言语法.

对于gfortran,Fortran 2003对可分配数组的分配在4.6,2011-01-28中引入.

同样注释,命令行选项-fno-realloc-lhs1禁用此自动(重新)分配,使编译器不符合Fortran 2003+.


1其他编译器具有类似的行为:添加必要的检查以确定是否需要重新分配是性能命中,这在Fortran 90兼容代码中是多余的,并且可能是许多人甚至在现代代码中都没有使用的功能.例如,对于英特尔的编译器,在某些支持F2003的版本中,默认值是忽略它.

人们总是可以通过使用数组部分来抑制现代代码中数组的(重新)分配检查/操作

array(:) = (/1,2,3/)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,array必须分配(如果可分配),等级1和大小为3,以使赋值语句有效.这与Fortran 90对整个阵列的赋值的解释一样array=(/1,2,3/).

这样做的原因是,使用此脚注的数组部分,左侧不可分配,即使数组本身是.


Don*_*nna 3

事实证明,只有 GNU gfortran 4.6 及更高版本允许在 F90 中自动重新分配 LHS 数组。使用编译器标志-fno-realloc-lhs会禁用此功能并触发 seg。我上面描述的所有情况下的故障(OSX、Linux、PPC)谜团已解决!感谢神秘发帖者的评论神秘消失。

请参阅GCC 4.6 维基百科

  • 不,他们不允许在 F90 中使用它,如果您使用严格的 Fortran 95 进行编译,则不应使用它。正如 francescalus 所解释的,这是 Fortran **2003** 功能。如果您的意思是在“.f90”文件中,那么是的,但这并不意味着 Fortran 90。 (3认同)
  • 区别 - 如果代码不符合特定标准的规则,则该标准不会指定会发生什么,这意味着就“正确行为”而言 - **任何事情都可能发生**。“任何事情”可以包括程序崩溃,或者程序进行某种神奇的重新分配,或者程序向你的老板写一封假辞职信,然后与你的配偶私奔。(实际可能发生的情况是另一个问题。) (3认同)