如何解决“C 指针技巧”允许不匹配的 Fortran 数组等级
我正在编写一个 HDF5 包装子例程,它将从/向 HDF5 文件内的数据集读/写 任何 形状的双精度数组。为了实现这一点,我使用了一些 C 指针技巧,这样子例程只接受数组的第一个元素作为 val
,但它实际上使用临时缓冲区 buf(1:sz_buf)
读取/写入整个数组。
到目前为止,我对 read 子程序有以下内容(在删除错误检查以保持简洁之后):
SUbroUTINE hdf5_read_array_d( fname,path,name,val,dims )
USE ISO_C_BINDING,ONLY: C_SIZE_T,C_LOC,C_F_POINTER
! Input arguments
CHaraCTER(LEN=*),INTENT(IN) :: fname,name
REAL(KIND(1.D0)),TARGET,INTENT(OUT) :: val
INTEGER,DIMENSION(:),INTENT(IN) :: dims
! Internal variables
INTEGER(KIND=HID_T) :: h5root,h5path,h5dset
INTEGER(KIND=HSIZE_T),DIMENSION(SIZE(dims)) :: h5dims
REAL(KIND(1.D0)),POINTER :: buf
INTEGER(KIND=C_SIZE_T) :: sz_buf
INTEGER :: dim
! Open the file in read-only mode
CALL h5fopen_f( TRIM(fname),H5F_ACC_RDONLY_F,h5root,ierr )
! Open the pre-existing path in the file as a group
CALL h5gopen_f( h5root,TRIM(path),ierr )
! Open the dataset
CALL h5dopen_f( h5path,TRIM(name),h5dset,ierr )
! Convert dims to HSIZE_T
h5dims(:) = dims(:)
! C pointer trickery: cast double -> void* -> double*
sz_buf = PRODUCT(dims)
ALLOCATE( buf( sz_buf ) )
CALL C_F_POINTER( C_LOC(val),buf,(/sz_buf/) )
! Read data from dataset through buffer
CALL h5dread_f( h5dset,H5T_NATIVE_DOUBLE,h5dims,ierr )
! Clean up and close HDF5 file
NULLIFY(buf)
CALL h5dclose_f( h5dset,ierr )
CALL h5gclose_f( h5path,ierr )
CALL h5fclose_f( h5root,ierr )
RETURN
END SUbroUTINE hdf5_read_array_d
现在,问题是,除了/代替DEALLOCATE(buf)
之外,我还需要放入NULLIFY(buf)
吗?
任何帮助将不胜感激。
注意:我知道 Fortran 2018 包含假定秩数组 val(..)
可以优雅地解决这个问题。但同样,这是一个较新的功能,可能尚未被所有编译器实现。
编辑:在 C_F_POINTER()
上,这是 Metcalf、Reid 和 Cohen(第 4 版,不是包含 Fortran 2018 内容的最新版本)的屏幕截图:
解决方法
您可以使用 C 风格的指针技巧来做您想做的事,但您在方法中需要解决一些问题:
- 您的
allocate(buf)
存在内存泄漏 - 你(巧妙地)在
val
的标量性质上撒谎 - 你会让任何阅读你代码的人都感到非常困惑
之所以如此令人困惑,是因为您不需要做这种诡计。这也是为什么我不会向您展示如何去做,或者解决“我需要取消分配和取消分配吗?”的问题。
您知道您有一个数组 val
可以将 n
值塞入一个连续的块中。您担心那不能这样做,因为您(不使用假定等级的虚拟对象)必须匹配数组形状。不用担心。
integer :: a(2,2,2),b(4,c(4,4)
都是具有 16 个元素的数组。也是
integer :: d(16)
您可以将实际参数 a
、b
和 c
与虚拟参数 d
相关联。让我们看看它的实际效果:
implicit none
integer :: a(2,4)
call set_them(a,SHAPE(a))
call set_them(b,SHAPE(b))
call set_them(c,SHAPE(c))
print '(16I3)',a,b,c
contains
subroutine set_them(d,dims)
integer,intent(in) :: dims(:)
integer,intent(out) :: d(PRODUCT(dims))
integer i
d=[(i,i=1,SIZE(d))]
end subroutine
end program
您甚至可以通过这种方式关联数组部分来定义部分。
您可以在此处看到有关此序列关联的其他几个问题,特别是查看数组形状的变化。这个答案更像是一种动机,即在尝试做一些复杂的事情时要寻找什么。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。