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

Posted

技术标签:

【中文标题】Fortran 中没有 Allocate() 的可变大小数组【英文标题】:Variable size arrays in Fortran without Allocate() 【发布时间】:2011-09-30 19:33:04 【问题描述】:

有没有办法在 Fortran 中创建可变大小的数组在堆栈上? Allocate() 对我不起作用,因为它将数组放在堆上。这可能会导致并行化问题(请参阅我的另一个问题: OpenMP: poor performance of heap arrays (stack arrays work fine))。当然,一些智能内存管理可以解决这个问题,但是 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 数组非常满意。如果对这个问题有否定的答案,我将非常感谢源链接。

编辑:见 cmets 到 M.S.B. 的回答。只有在 Fortran 2008 中才能实现这种优雅的方式,并且它是在 block 构造中完成的。

【问题讨论】:

【参考方案1】:

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

subroutine MySub ( N )

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

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

您还可以将可分配数组作为实际参数传递给子例程,而无需将子例程的虚拟参数声明为可分配的。这可能对您的担忧没有帮助,因为原始数组可能仍然在堆上。

【讨论】:

谢谢,M.S.B.!与 C 的 int array[N] 相比,它虽然重,但它确实有效。 您可以使用 Fortran 2008 的块结构做一些更接近 C 的事情,即在代码中间声明。参见,例如,p。 ftp.nag.co.uk/sc22wg5/N1701-N1750/N1729.pdf 中的 12 个。我不知道哪些编译器支持这个,或者他们是否支持 OpenMP。 我的代码中有这个结构,但是我注意到默认情况下 gfortran 仍然将数组放在堆上,现在我在紧密循环的中间有 malloc。似乎需要“-fstack-arrays”选项。 只是提供一些我知道的历史。子例程中的可变大小数组(自动数组)作为数值计算的有用特性,自(或之前)Fortran77 以来就受支持,而 C 仅从 C99 开始支持此功能。 Linus Torvalds 过去曾表达过他对使用 cmets 的可变长度数组的不满,例如“使用 VLA 是积极愚蠢的!与仅使用固定的密钥大小相比,它会生成更多的代码和更慢的代码(以及更脆弱的代码)。''【参考方案2】:

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

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

其他编译器可能有类似的选项。也许这可以满足您的需求。

【讨论】:

谢谢,这是一个有趣的想法!但是,适用于此的“本地”数组是在函数中创建的数组,数组大小作为 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:是的,我担心这个特殊选项不能完全满足您的需求。 Gcc 4.4.3 有点老了,特别是从 Fortran 的角度来看; gfortran 开发一直(并且仍然)非常活跃。如果可能,您可以尝试更新版本是否仍然存在相同的问题。另外,如果我是你,我会在 gfortran 邮件列表上问你的问题。由于这涉及实施的细节,因此开发人员最清楚什么是可能的,什么是不可能的。

以上是关于Fortran 中没有 Allocate() 的可变大小数组的主要内容,如果未能解决你的问题,请参考以下文章

vs 2015写fortran执行后无法输入

fortran子程序中可以用动态数组吗??

用于 Fortran 的 mex 网关中 REAL 变量的可移植声明

在fortran中只为二维数组分配一维

fortran中format如何保留两位小数

GDB 可以用于在 Fortran 90 中打印派生类型的可分配数组的值吗? [复制]