问题描述
我有一个分配的数组A Fortran程序如下:
I have a fortran program with an allocatable array A as follows:
real, dimension(:,:) allocatable :: A
...
allocate(A(x0:x1;y0:y1))
这阵最终作为参数传递给一个子程序,看起来像通过
This array is eventually passed as argument to a subroutine which looks like
subroutine my_subroutine(arr)
real, dimension(x0:x1,y0:y1) :: arr
...
end subroutine my_subroutine
我想通过一个自定义的内存分配函数my_alloc在C库中实现,以取代Fortran语言的分配的声明。目前,我改变了最初的code样品为:
I wanted to replace the "allocate" statement of Fortran by a custom memory allocation function "my_alloc" implemented in a C library. Currently I changed the first code sample into:
type(c_ptr) :: cptr
real, pointer, dimension(:,:) :: A
...
cptr = my_alloc(...)
call c_f_pointer(cptr,A,[x1-x0+1,y1-y0+1])
这工作得很好,除了通过指定,而不是在C_F_POINTER功能下/上限范围,我失去了原来的形状的数组(X0:Y1:X1,Y0)。但是,这不是一个大问题:指针路人的子程序的说法,子程序期待一个数组,并考虑指针数组,用正确的边界
This works fine, except that by specifying extents instead of lower/upper bounds in the c_f_pointer function, I lose the original shape (x0:x1,y0:y1) of the array. But this is not a big problem: the pointer is passer as argument of the subroutine, the subroutine expect an array and consider the pointer as an array, with the proper bounds.
我的真正的问题是:当我想也改写子程序的code有一个指针,而不是数组
My real problem is: when I want to also rewrite the subroutine's code to have a pointer instead of an array.
subroutine my_subroutine(arr)
real, pointer, dimension(x0:x1,y0:y1) :: arr
...
end subroutine my_subroutine
上面的code不工作; gfortran说:数组指针'改编'在(1)必须有延迟的外形
The code above doesn't work; gfortran says: Array pointer 'arr' at (1) must have a deferred shape
以下code可以编译:
the following code can be compiled:
subroutine my_subroutine(arr)
real, pointer, dimension(:,:) :: arr
...
end subroutine my_subroutine
但是,当我试图执行一个循环从X0到X1和从Y0到Y1它不提供的范围和程序崩溃。
But it doesn't provide the bounds and the program crashes when I try to perform a loop from x0 to x1 and from y0 to y1.
我该如何处理这种情况?在子程序,我需要FORTRAN知道ARR是一个指针形数组(X0:X1,Y0,Y1)
How can I handle this case? Within the subroutine, I need fortran to know that arr is a pointer to an array shaped (x0:x1,y0;y1).
感谢
推荐答案
是的,这是因为C_F_POINTER的限制的问题。正如你所发现的内在C_F_POINTER只支持范围从索引1.人们经常指出,Fortran语言是一个索引语言,但这不是真的。一个索引仅默认和Fortran长期以来一直支持声明的约束,程序员想要的任何起点。所以这是一种倒退的C_F_POINTER强迫你使用一个索引。但与2003年的Fortran有修补程序:指针边界重新映射:
Yes, this was a problem because of the limitation of c_f_pointer. As you have found the intrinsic c_f_pointer only supports bounds starting at index 1. People frequently state that Fortran is a one-indexed language but this not true. One indexing is only the default and Fortran has long supported declaring any starting bound that the programmer wants. So it was a step backwards that c_f_pointer forced you to use one indexing. But with Fortran 2003 there is a fix: pointer bounds remapping:
arr (0:n-1) => arr
而不是1:N,或任何你想
instead of 1:n, or whatever you wish.
然后通过数组的子程序,它会收到预期的范围。
Then pass the array to the subroutine and it will receive the intended bounds.
编辑:改善显示allocatables和指针之间的区别演示程序。指针经过阵列的边界。一个规则的数组传递的形状......你可以宣布第一个维度的子程序,如果你愿意,并让形状控制第二。
improve demo program showing the difference between allocatables and pointers. The pointer passes the bounds of the array. A regular array passes the shape ... you can declare the first dimension in a subroutine, if you wish, and let the shape control the second.
module mysubs
implicit none
contains
subroutine testsub ( ptr, alloc, start, array )
real, pointer, dimension (:) :: ptr
real, dimension (:), intent (in) :: alloc
integer, intent (in) :: start
real, dimension (start:), intent (in) :: array
write (*, *) "pointer in sub:", lbound (ptr, 1), ubound (ptr, 1)
write (*, *) ptr
write (*, *) "1st array in sub:", lbound (alloc, 1), ubound (alloc, 1)
write (*, *) alloc
write (*, *) "2nd array in sub:", lbound (array, 1), ubound (array, 1)
write (*, *) array
return
end subroutine testsub
end module mysubs
program test_ptr_assignment
use mysubs
implicit none
real, pointer, dimension(:) :: test
real, allocatable, dimension(:) :: alloc1, alloc2
real, allocatable, dimension(:) :: alloc1B, alloc2B
allocate ( test (1:5), alloc1 (1:5), alloc1B (1:5) )
test = [ 1.0, 2.0, 3.0, 4.0, 5.0 ]
alloc1 = test
alloc1B = test
write (*, *) "A:", lbound (test, 1), ubound (test, 1)
write (*, *) test
call testsub (test, alloc1, 1, alloc1B )
test (0:4) => test
allocate ( alloc2 (0:4), alloc2B (0:4) )
alloc2 = test
alloc2B = test
write (*, *)
write (*, *) "B:", lbound (test, 1), ubound (test, 1)
write (*, *) test
call testsub (test, alloc2, 0, alloc2B)
stop
end program test_ptr_assignment
这篇关于FORTRAN:分配数组和指针的等价的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!