我们最近发现我们正在为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;
}
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
输出(运行时)是:
Array is NOT allocated
Array is allocated
size is 5
0.0000000000000000
1.0000000000000000
2.0000000000000000
3.0000000000000000
4.0000000000000000
以下是Power PC上的输出:
Array is NOT allocated
Segmentation fault (core dumped)
总结:它在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实现仅在代码中稍后进行了细分,其中引用了分配数组的条目,从而使我们的错误变为“错误”。 (如果它实际上是一个bug)真的很难追查。
上述代码的正确行为是什么?
答案 0 :(得分:21)
代码的有效性,如
integer, allocatable :: array(:)
array = (/1,2,3/)
end
取决于用于解释它的Fortran标准。
Fortran 2003引入了内在赋值的自动分配概念。在Fortran 2003之前,必须分配这样一个赋值语句左侧的数组,并且形状与右侧的数组相同。
从Fortran 2003开始,只有排名需要匹配。如果存在形状不匹配,则首先释放阵列,然后重新分配到正确的形状。如果最初没有分配,则会被分配。
因此,上面的程序并不是有效的Fortran 90,但它是有效的Fortran 2003。
然后,真实世界代码的不同之处在于编译器支持的语言语法。
对于gfortran,Fortran 2003对可分配数组的赋值是introduced in 4.6, 2011-01-28。
同样注释,命令行选项-fno-realloc-lhs
1 禁用此自动(重新)分配,使编译器不符合Fortran 2003+。
1 其他编译器具有类似的行为:添加必要的检查以确定是否需要重新分配是性能损失,这在Fortran 90兼容代码中是多余的,并且可能是许多人未使用的功能码。例如,对于Intel's compiler,在某些支持F2003的版本中,默认值是忽略它。
总是可以通过使用数组部分来抑制现代代码中数组的(重新)分配检查/操作
array(:) = (/1,2,3/)
在这种情况下,必须为array
(如果可分配)分配等级1和大小为3,以使赋值语句有效。这与使用整个数组array=(/1,2,3/)
的赋值的Fortran 90解释一样。
这样做的原因是,使用此脚注的数组部分,左侧不可分配,即使数组本身是。
答案 1 :(得分:3)
事实证明,只有GNU gfortran 4.6及以上允许在F90中自动重新分配LHS阵列。使用编译器标志Foo::new_default(i)
禁用此功能并触发seg。我在上面描述的所有情况下的错误(OSX,Linux,PPC)神秘解决了!感谢神秘的海报,其评论神秘地消失了。
请参阅GCC 4.6 Wiki