因为我也不确定reshape() 是否会在连续情况下创建一个临时数组,所以我尝试打印原始地址并通过c_loc() 传递数组。然后,即使对于小的一维数组,gfortran-8 和 ifort-16 中的reshape() 似乎也会创建临时对象(因为第一个元素的地址不同)。因此,假设即使对于简单的情况也会创建临时对象似乎更安全(有关更多信息,请参阅下面 francescalus 的 cmets。)
module test
use iso_c_binding, only: c_loc
implicit none
interface linear
module procedure linear_r2d, linear_r3d
endinterface
contains
subroutine calc_ver1( a ) !! assumed-shape dummy array
real, contiguous, target :: a(:)
print *, "addr = ", c_loc( a(1) )
print *, "vals = ", a
endsubroutine
subroutine calc_ver2( a, n ) !! explicit-shape dummy array
integer :: n
real, target :: a( n )
print *, "addr = ", c_loc( a(1) )
print *, "vals = ", a
endsubroutine
function linear_r2d( a ) result( ptr ) !! returns a 1-d pointer from 2-d array
real, contiguous, target :: a(:,:)
real, contiguous, pointer :: ptr(:)
ptr( 1 : size(a) ) => a
endfunction
function linear_r3d( a ) result( ptr ) !! returns a 1-d pointer from 3-d array
real, contiguous, target :: a(:,:,:)
real, contiguous, pointer :: ptr(:)
ptr( 1 : size(a) ) => a
endfunction
endmodule
program main
use test
implicit none
integer i
real, target :: a(2), b(2,2), c(2,2,2)
a = [1,2]
b = reshape( [( 2*i, i=1,4 )], [2,2] )
c = reshape( [( 3*i, i=1,8 )], [2,2,2] )
print *, "addr(a) = ", c_loc( a(1) )
print *, "addr(b) = ", c_loc( b(1,1) )
print *, "addr(c) = ", c_loc( c(1,1,1) )
print *, "[ use assumed-shape dummy ]"
call calc_ver1( a )
! call calc_ver1( b ) ! rank mismatch
! call calc_ver1( c ) ! rank mismatch
print *, "--- with reshape() ---"
call calc_ver1( reshape( b, [size(b)] ) )
call calc_ver1( reshape( c, [size(c)] ) )
print *, "--- with linear() ---"
call calc_ver1( linear( b ) )
call calc_ver1( linear( c ) )
print *
print *, "[ use explicit-shape dummy ]"
call calc_ver2( a, size(a) )
call calc_ver2( b, size(b) )
call calc_ver2( c, size(c) )
end
ifort-16 在 Linux 上的结果:
addr(a) = 7040528
addr(b) = 7040544
addr(c) = 7040560
[ use assumed-shape dummy ]
addr = 7040528
vals = 1.000000 2.000000
--- with reshape() ---
addr = 140736361693536
vals = 2.000000 4.000000 6.000000 8.000000
addr = 140736361693560
vals = 3.000000 6.000000 9.000000 12.00000 15.00000 18.00000 21.00000 24.00000
--- with linear() ---
addr = 7040544
vals = 2.000000 4.000000 6.000000 8.000000
addr = 7040560
vals = 3.000000 6.000000 9.000000 12.00000 15.00000 18.00000 21.00000 24.00000
[ use explicit-shape dummy ]
addr = 7040528
vals = 1.000000 2.000000
addr = 7040544
vals = 2.000000 4.000000 6.000000 8.000000
addr = 7040560
vals = 3.000000 6.000000 9.000000 12.00000 15.00000 18.00000 21.00000 24.00000
gfortran-8 在 OSX10.11 上的结果:
addr(a) = 140734555734776
addr(b) = 140734555734752
addr(c) = 140734555734720
[ use assumed-shape dummy ]
addr = 140734555734776
vals = 1.00000000 2.00000000
--- with reshape() ---
addr = 140734555734672
vals = 2.00000000 4.00000000 6.00000000 8.00000000
addr = 140734555733984
vals = 3.00000000 6.00000000 9.00000000 12.0000000 15.0000000 18.0000000 21.0000000 24.0000000
--- with linear() ---
addr = 140734555734752
vals = 2.00000000 4.00000000 6.00000000 8.00000000
addr = 140734555734720
vals = 3.00000000 6.00000000 9.00000000 12.0000000 15.0000000 18.0000000 21.0000000 24.0000000
[ use explicit-shape dummy ]
addr = 140734555734776
vals = 1.00000000 2.00000000
addr = 140734555734752
vals = 2.00000000 4.00000000 6.00000000 8.00000000
addr = 140734555734720
vals = 3.00000000 6.00000000 9.00000000 12.0000000 15.0000000 18.0000000 21.0000000 24.0000000
而且我还认为,根据情况,显式形状的虚拟数组很有用,并且问题中的代码似乎正是这种情况。 (因为实际参数是连续的,所以没有临时创建数组。)如果不需要calc_ver2() 中的大小参数n,我们可以使用返回一维数组指针的函数(参见上面的linear() ),但考虑到calc_ver2() 的简单性,我想这可能有点矫枉过正。(顺便说一句,我在代码的各个位置附加了target,这仅仅是因为c_loc() 需要它)。