基本上有两种方法可以将数组传递给Fortran 90/95中的子程序:
PROGRAM ARRAY
INTEGER, ALLOCATABLE :: A(:,:)
INTEGER :: N
ALLOCATE(A(N,N))
CALL ARRAY_EXPLICIT(A,N)
! or
CALL ARRAY_ASSUMED(A)
END PROGRAM ARRAY
SUBROUTINE ARRAY_EXPLICIT(A,N)
INTEGER :: N
INTEGER :: A(N,N)
! bla bla
END SUBROUTINE ARRAY_EXPLICIT
SUBROUTINE ARRAY_ASSUMED(A)
INTEGER, ALLOCATABLE :: A(:,:)
N=SIZE(A,1)
! bla bla
END SUBROUTINE ARRAY_ASSUMED
Run Code Online (Sandbox Code Playgroud)
您需要第二个显式接口,通常是通过使用模块.
从FORTRAN77开始,我习惯了第一种选择,如果你传递整个数组,我认为这也是最有效的.
显式形状的好处是我也可以调用子例程并将数组视为向量而不是矩阵:
SUBROUTINE ARRAY_EXPLICIT(A,N)
INTEGER :: N
INTEGER :: A(N**2)
! bla bla
END SUBROUTINE ARRAY_EXPLICIT
Run Code Online (Sandbox Code Playgroud)
我想知道是否有一种很好的方法来使用第二个假定的形状界面来做这种事情而不复制它.
参见RESHAPE内在,例如
http://gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html
或者,如果你想避免副本(在某些情况下,优化编译器可能能够在不复制的情况下进行重构,例如,如果之后不使用RHS数组,但我不会指望它),从Fortran 2003开始您可以使用边界重新映射为不同等级的目标指定指针.比如像
program ptrtest
real, pointer :: a(:)
real, pointer :: b(:,:)
integer :: n = 10
allocate(a(n**2))
a = 42
b (1:n, 1:n) => a
end program ptrtest
Run Code Online (Sandbox Code Playgroud)
小智 8
我本来想做同样的事情并且遇到了这个讨论.没有一个解决方案适合我的目的,但我发现如果你使用当前fortran 90/95编译器倾向于支持的fortran 2003标准,有一种方法可以重塑数组而不使用iso_c_binding复制数据.我知道讨论已经过时了,但我想我会在这个问题的基础上为其他人的利益添加我想出的内容.
关键是使用函数C_LOC将数组转换为数组指针,然后使用C_F_POINTER将其转换回具有所需形状的fortran数组指针.使用C_LOC的一个挑战是C_LOC仅适用于具有直接指定形状的数组.这是因为具有不完整大小规范的fortran中的数组(即,对于某些维度使用:)包括数组描述符以及数组数据.C_LOC不会为您提供数组数据的内存位置,而是提供描述符的位置.因此,可分配数组或指针数组不能与C_LOC一起使用(除非您需要编译器特定数组描述符数据结构的位置).解决方案是创建一个子例程或函数,将数组作为固定大小的数组接收(大小确实无关紧要).这会导致函数(或子例程)中的数组变量指向数组数据的位置,而不是数组描述符的位置.然后使用C_LOC获取指向数组数据位置的指针,使用C_F_POINTER将此指针转换回具有所需形状的数组.必须将所需的形状传递给此函数以与C_F_POINTER一起使用.以下是一个例子:
program arrayresize
implicit none
integer, allocatable :: array1(:)
integer, pointer :: array2(:,:)
! allocate and initialize array1
allocate(array1(6))
array1 = (/1,2,3,4,5,6/)
! This starts out initialized to 2
print *, 'array1(2) = ', array1(2)
! Point array2 to same data as array1. The shape of array2
! is passed in as an array of intergers because C_F_POINTER
! uses and array of intergers as a SIZE parameter.
array2 => getArray(array1, (/2,3/))
! Change the value at array2(2,1) (same as array1(2))
array2(2,1) = 5
! Show that data in array1(2) was modified by changing
! array2(2,1)
print *, 'array(2,1) = array1(2) = ', array1(2)
contains
function getArray(array, shape_) result(aptr)
use iso_c_binding, only: C_LOC, C_F_POINTER
! Pass in the array as an array of fixed size so that there
! is no array descriptor associated with it. This means we
! can get a pointer to the location of the data using C_LOC
integer, target :: array(1)
integer :: shape_(:)
integer, pointer :: aptr(:,:)
! Use C_LOC to get the start location of the array data, and
! use C_F_POINTER to turn this into a fortran pointer (aptr).
! Note that we need to specify the shape of the pointer using an
! integer array.
call C_F_POINTER(C_LOC(array), aptr, shape_)
end function
end program
Run Code Online (Sandbox Code Playgroud)
@janneb已经回答了重新回复.RESHAPE是一个函数 - 通常在赋值语句中使用,因此将有一个复制操作.也许它可以在不使用指针进行复制的情况下完成.除非阵列很大,否则最好使用RESHAPE.
我怀疑显式形状数组在运行时方面比假设形状更有效.我倾向于使用Fortran> = 90语言的特性并使用假定的形状声明......这样你就不必费心去传递尺寸了.
编辑:我用ifort 11,gfortran 4.5和gfortran 4.6测试了@janneb的示例程序.在这三个中,它仅适用于gfortran 4.6.有趣的是,要转向另一个方向并将1-D阵列连接到现有的2-D阵列,需要Fortran 2008的另一个新功能,即"连续"属性 - 至少根据gfortran 4.6.0 20110318.在没有此属性的情况下声明,有一个编译时错误.
program test_ptrs
implicit none
integer :: i, j
real, dimension (:,:), pointer, contiguous :: array_twod
real, dimension (:), pointer :: array_oned
allocate ( array_twod (2,2) )
do i=1,2
do j=1,2
array_twod (i,j) = i*j
end do
end do
array_oned (1:4) => array_twod
write (*, *) array_oned
stop
end program test_ptrs
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
25019 次 |
| 最近记录: |