问题 Fortran中的可变大小数组,没有Allocate()


有没有办法在Fortran中创建可变大小的数组 在堆栈上? Allocate()对我不起作用,因为它将数组放在堆上。这可能会导致并行化问题(请参阅我的其他问题: OpenMP:堆数组性能不佳(堆栈数组工作正常) )。当然,一些智能内存管理会解决这个问题,但Fortran中的内存管理听起来很愚蠢。

基本上,我在C中寻找与以下相同的Fortran:

scanf("%d", N);
int myarray[N];

重新迭代:我不想要

Integer, PARAMETER :: N=100
Integer, Dimension(N) :: myarray

因为这决定了编译时的数组大小。我也不想要

Integer, Dimension(:), Allocatable :: myarray
read(*,*) N
Allocate(myarray(1:N))

因为它将数组放在堆上。

非常感谢帮助。在我最近遇到上述问题中的问题之前,我对Allocatable阵列非常满意。如果对这个问题有一个否定的答案,我非常感谢与该来源的链接。

编辑:请参阅M.S.B.的回答。这样做的一种优雅方式只能在Fortran 2008中实现,而且它是在一个完成的 block 构造。


5230
2017-07-07 20:51


起源



答案:


只要维度在运行时已知,Fortran就可以自动创建数组,只要在子程序的入口处有声明...这不需要将维度声明为参数属性,它们可以是参数,例如,

subroutine MySub ( N )

integer, intent (in) :: N
real, dimension (N) :: array

已验证。那么为什么不在主程序或某个子程序中决定你的大小“N”,然后调用另一个子程序继续。可能这种方法阵列将在堆栈上。正如@eriktous所写,Fortran语言标准没有指定这种行为。有些编译器将本地数组切换到超过一定大小的堆。某些编译器提供了控制此行为的选项。将大型数组放在堆上可能会被递归或OpenMP覆盖。

您还可以将可分配数组作为实际参数传递给子例程,而不将子例程的伪参数声明为可分配。这可能无助于您的关注,因为原始数组仍可能在堆上。


11
2017-07-08 01:33



谢谢,M.S.B。!与C相比,它很重 int array[N],它的诀窍。 - drlemon
您可以使用Fortran 2008的块构造,更接近C,即代码中间的声明。例如,参见p。 12的 ftp.nag.co.uk/sc22wg5/N1701-N1750/N1729.pdf。我不知道哪些编译器支持这个,或者他们是否支持OpenMP。 - M. S. B.
我在我的代码中有这个构造,但是我注意到默认情况下gfortran仍然将数组放在堆上,现在我在紧密循环中间有malloc。似乎需要选项“-fstack-arrays”。 - DaveP


答案:


只要维度在运行时已知,Fortran就可以自动创建数组,只要在子程序的入口处有声明...这不需要将维度声明为参数属性,它们可以是参数,例如,

subroutine MySub ( N )

integer, intent (in) :: N
real, dimension (N) :: array

已验证。那么为什么不在主程序或某个子程序中决定你的大小“N”,然后调用另一个子程序继续。可能这种方法阵列将在堆栈上。正如@eriktous所写,Fortran语言标准没有指定这种行为。有些编译器将本地数组切换到超过一定大小的堆。某些编译器提供了控制此行为的选项。将大型数组放在堆上可能会被递归或OpenMP覆盖。

您还可以将可分配数组作为实际参数传递给子例程,而不将子例程的伪参数声明为可分配。这可能无助于您的关注,因为原始数组仍可能在堆上。


11
2017-07-08 01:33



谢谢,M.S.B。!与C相比,它很重 int array[N],它的诀窍。 - drlemon
您可以使用Fortran 2008的块构造,更接近C,即代码中间的声明。例如,参见p。 12的 ftp.nag.co.uk/sc22wg5/N1701-N1750/N1729.pdf。我不知道哪些编译器支持这个,或者他们是否支持OpenMP。 - M. S. B.
我在我的代码中有这个构造,但是我注意到默认情况下gfortran仍然将数组放在堆上,现在我在紧密循环中间有malloc。似乎需要选项“-fstack-arrays”。 - DaveP


Fortran标准没有堆栈和堆的概念,因此这将依赖于实现(即编译器)。查看文档,例如gfortran,它有一个选项

-frecursive
    通过强制在堆栈上分配所有本地数组来允许间接递归。

其他编译器可能有类似的选择。也许这就是你想要的。


5
2017-07-07 21:56



谢谢,这是一个有趣的想法!但是,适用于此的“本地”数组是在函数中创建的数组,数组大小作为intent(in)参数传递给它。在我的测试中,-frecursive对Allocate()的结果没有影响,但确实对这个有趣的解决方法有影响: subroutine doit(n); integer, intent(in) :: n; integer, dimension(1:n) :: myarray; ! blah ; end subroutine ... read(*,*) n; call doit(n) 在这种情况下,myarray似乎在有和没有-frecursive的情况下进入堆栈。有点变态,但诀窍。我在x86_64上使用gcc 4.4.3。 - drlemon
@drlemon:是的,我担心这个特殊选项不会完全按照你的需要做。 Gcc 4.4.3有点陈旧,特别是从Fortran的角度来看; gfortran开发一直(并且仍然)非常活跃。如果可能,您可以尝试新版本仍然存在相同的问题。另外,如果我是你,我会在gfortran邮件列表上问你的问题。由于这涉及到实现的细节,开发人员会最清楚地知道什么是可能的,什么不是。 - eriktous