使用 c_f_pointer 是 fortran 数组是否就地重塑

jbd*_*bdv 3 fortran in-place reshape fortran-iso-c-binding

我有一个与几年前在英特尔开发人员论坛上提出的有关就地重构阵列的问题相关的问题。

简而言之,答案是可以分配特定等级的数组,并创建一个指向相同内存位置(即就地)但具有不同等级的指针,例如:

use, intrinsic :: ISO_C_BINDING
integer, allocatable, target :: rank1_array(:)
integer, pointer :: rank3_array(:,:,:)
integer :: i

! Allocate rank1_array 
allocate(rank1_array(24))

! Created rank3_pointer to rank1_array
call C_F_POINTER (C_LOC(rank1_array), rank3_array, [3,2,4])

! Now rank3_array is the same data as rank1_array, but a 3-dimension array with bounds (3,2,4)
Run Code Online (Sandbox Code Playgroud)

我现在的问题是,如果我deallocate是原始数组rank1_array,为什么指针rank3_array仍然关联,并且可以毫无问题地使用(似乎)。因此,如果我附加上面的代码段:

! initialise the allocated array
rank1_array = [(i, i=1,24)]

! then deallocate it
deallocate(rank1_array)

! now do stuff with the pointer
print *, associated(rank3_array)
rank3_array(2,2,1) = 99
print *, rank3_array
Run Code Online (Sandbox Code Playgroud)

编译和运行这个程序给了我输出

gfortran -Wall my_reshape.f90 -o my_reshape
./my_reshape
T
1 2 3 4 99 6 7 ... 23 24
Run Code Online (Sandbox Code Playgroud)

如果 的内存rank1_array被释放,为什么rank3_array除非它是原始的副本,否则仍然起作用?最初的重塑是否就位?如果有人能向我解释这种行为,我将不胜感激。

我正在使用感兴趣的 gfortran 6.1.0。

编辑/更新:

正如@francescalus 接受的答案所表明的那样,这里的真正问题是我如何(错误地!)一般地处理指针,而不是C_F_POINTER特别是就地重塑。我看到的奇怪行为只是由于我编写的不兼容的 Fortran 代码导致的未定义行为的结果。基于@francescalus 的回答和评论,我在网上做了更多阅读,并认为提供指向Fortran 参考手册相关部分的链接可能很有用,该手册非常清楚地解释了如何处理指针和可分配数组。

fra*_*lus 5

c_f_pointer是用来代替“正常”指针赋值是不相关的问题,也不是改变形状。

调用后c_f_pointer的指针rank3_array是与目标相关联的指针rank1_array。没有复制。

何时rank1_array在语句中解除分配

 deallocate(rank1_array)
Run Code Online (Sandbox Code Playgroud)

这对rank1_array作为目标的指针有影响。特别是,指针关联状态rank3_array变为undefined。(每当指针的目标被解除分配时,除非通过指针,指针的关联状态变为未定义。)

与未定义关联状态的指针下一部分

print *, associated(rank3_array)
Run Code Online (Sandbox Code Playgroud)

不被允许。在这一点上,该程序不是 Fortran 兼容程序(并且编译器不需要检测到这一点),并且处理器可以.TRUE.在需要时在此处打印。

同样,与

rank3_array(2,2,1) = 99
print *, rank3_array
Run Code Online (Sandbox Code Playgroud)

rank3_array本身是未定义的,也不允许这些引用。同样,编译器可以使用任何效果。

现在,就像在类似主题的另一个答案中一样:仅仅因为rank1_array已被释放并不意味着内存被清除。可能发生的只是第一个数组的某个数组描述符的状态发生了变化。对所有相关的指针/描述符做同样的事情不是编译器的责任。(因此指针的描述符可能确实仍然说“关联”。)

不过,重要的是要注意:它可能看起来有效,但我不建议将您的工作押在它上面。