【发布时间】:2016-10-23 03:45:53
【问题描述】:
在现代 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 参数派生的,并且该修复尚未包含在二进制版本中。
【问题讨论】:
标签: arrays fortran return-value return-by-reference return-by-value