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"。)
尽管如此,请务必注意:它可能看起来很有效,但我不建议将您的工作押注于此。
我有一个问题与几年前在 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"。)
尽管如此,请务必注意:它可能看起来很有效,但我不建议将您的工作押注于此。