与c_f_pointer是fortran数组重塑原位或不原样

时间:2017-06-08 22:27:42

标签: fortran reshape in-place fortran-iso-c-binding

我有一个问题与几年前在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。

修改/更新

正如@francescalus所接受的答案所指出的,这里真正的问题是我(错误!)如何处理指针,而不是特别是C_F_POINTER的就地重塑。我看到的奇怪行为只是由于我编写的不合规的fortran代码导致的未定义行为。基于@francescalus的回答和评论,我做了更多的在线阅读,并认为给一个Fortran Reference Manual的相关部分的链接可能是有用的,它可以非常清楚地解释如何处理指针和可分配的数组。

1 个答案:

答案 0 :(得分:4)

使用c_f_pointer代替"正常"指针赋值与问题无关,也不会改变形状。

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

在声明

中取消分配rank1_array
 deallocate(rank1_array)

这会对以rank1_array为目标的指针产生影响。特别是,rank3_array的指针关联状态变为未定义。 (每当指针的目标被释放,除非通过指针,指针的关联状态变为未定义。)

指定未定义关联状态的指针

print *, associated(rank3_array)

是不允许的。此时程序不是符合Fortran标准的程序(并且编译器无法检测到该程序),如果需要,处理器可以在此处打印.TRUE.

同样,

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

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

现在,就像在another answer中关于类似主题的那样:只是因为rank1_array已被解除分配,并不意味着内存被清除。可能发生的一切是第一个数组的某个数组描述符的状态发生了变化。编译器的责任不是对所有相关的指针/描述符执行相同的操作。 (所以指针的描述符可能仍然会说"关联"。)

但是,重要的是要注意:它可能看起来像是在工作,但我不建议在你的工作上下注。