with c_f_pointer 是否就地重塑 Fortran 数组

with c_f_pointer is fortran array reshape in-place or not

我有一个问题与几年前在 Intel Developer Forum 上提出的关于数组的就地重塑的问题有关。

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

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)

我现在的问题是,如果我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

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

gfortran -Wall my_reshape.f90 -o my_reshape
./my_reshape
T
1 2 3 4 99 6 7 ... 23 24

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

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

Edit/Update:

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

使用 c_f_pointer 而不是 "normal" 指针赋值与问题无关,改变形状也不相关。

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

rank1_array在语句中释放时

 deallocate(rank1_array)

这对以 rank1_array 作为目标的指针有影响。特别是,rank3_array 的指针关联状态变为 undefined。 (只要指针的目标被释放,除非通过指针,指针的关联状态变为未定义。)

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

print *, associated(rank3_array)

不允许。此时该程序不是 Fortran 兼容程序(并且编译器不需要检测)并且允许处理器在此处打印 .TRUE. 如果需要的话。

同样,与

rank3_array(2,2,1) = 99
print *, rank3_array

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

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

尽管如此,请务必注意:它可能看起来很有效,但我不建议将您的工作押注于此。