在现代 Fortran 中是否可以从函数返回一个数组,其性能相当于让子例程填充作为参数传递的数组?
考虑例如作为简单的例子
PROGRAM PRETURN
INTEGER :: C(5)
C = FUNC()
WRITE(*,*) C
CALL SUB(C)
WRITE(*,*) C
CONTAINS
FUNCTION FUNC() RESULT(X)
INTEGER :: X(5)
X = [1,2,3,4,5]
END FUNCTION FUNC
SUBROUTINE SUB(X)
INTEGER :: X(5)
X = [1,2,3,4,5]
END SUBROUTINE SUB
END PROGRAM PRETURN
在这里,该行C = FUNC()
将从函数返回值中复制值,然后从堆栈中丢弃返回的数组。子例程版本CALL SUB(C)
将直接填充C
,避免了与临时数组相关的额外应对步骤和内存使用——但在表达式中使用却是SUM(FUNC())
不可能的。
但是,如果编译器实现选择在堆上分配所有数组,则可以简单地通过更改底层指针来分配返回值C
,从而在两个版本之间实现相同的性能。*
这种优化是由常见的编译器进行的,还是有其他方法可以在没有性能开销的情况下获得函数语义?
* 使用可分配数组会更明显,但这会遇到编译器支持问题。默认情况下,英特尔 fortran 在分配不同大小的数组时不会(重新)分配数组,但通过使用ALLOCATE(C, SOURCE=FUNC())
语句允许相同的效果。Gfortran 同时在分配时进行自动分配,但有一个错误会阻止ALLOCATE
从参数派生形状的语句,SOURCE
并且该修复尚未包含在二进制版本中。