Pointers &引用;C指针欺骗”;允许不匹配的Fortran数组列组

Pointers &引用;C指针欺骗”;允许不匹配的Fortran数组列组,pointers,fortran,fortran-iso-c-binding,Pointers,Fortran,Fortran Iso C Binding,我正在编写一个HDF5包装子例程,它将从HDF5文件中的数据集读取/写入任意形状的双精度数组。为了实现这一点,我使用了一些C指针技巧,这样子例程只接受数组的第一个元素val,但实际上它使用临时缓冲区buf(1:sz_-buf)读取/写入整个数组 到目前为止,我对read子例程有以下内容(在删除错误检查以保持简洁性之后): 现在的问题是,除了取消分配(buf),我是否还需要加入取消分配(buf) 任何帮助都将不胜感激 注:我知道Fortran 2018包含假定的秩数组val(..),这将优雅地解决

我正在编写一个HDF5包装子例程,它将从HDF5文件中的数据集读取/写入任意形状的双精度数组。为了实现这一点,我使用了一些C指针技巧,这样子例程只接受数组的第一个元素
val
,但实际上它使用临时缓冲区
buf(1:sz_-buf)
读取/写入整个数组

到目前为止,我对read子例程有以下内容(在删除错误检查以保持简洁性之后):

现在的问题是,除了
取消分配(buf)
,我是否还需要加入
取消分配(buf)

任何帮助都将不胜感激

注:我知道Fortran 2018包含假定的秩数组
val(..)
,这将优雅地解决此问题。但同样,这是一个更新的特性,可能还没有被所有的编译器实现

编辑:在
C\u F\u POINTER()
上,这里是Metcalf、Reid和Cohen的截图(第四版,不是最新的Fortran 2018版本):

您可以使用C风格的指针技巧来做您想做的事情,但在您的方法中需要解决一些问题:

  • 您的
    allocate(buf)
  • 关于
    val
  • 你会让任何阅读你代码的人感到非常困惑
这让人非常困惑的原因是,你不需要这样做。这也是为什么我不会向您展示如何做,或者解决“我需要取消分配和取消分配吗?”

你知道你有一个数组
val
来填充
n
值,在一个连续的块中。您担心这样做不行,因为您(不使用假定的秩虚拟)必须匹配数组形状。别担心

  integer :: a(2,2,2,2), b(4,2,2), c(4,4)
都是包含16个元素的数组。也是如此

  integer :: d(16)
您可以将实际参数
a
b
c
与伪参数
d
相关联。让我们看看实际情况:

  implicit none

  integer :: a(2,2,2,2), b(4,2,2), c(4,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
您甚至可以通过这种方式关联阵列节来定义部分


您可以在这里看到关于这个序列关联的其他几个问题,特别是关于数组形状的变化。这个答案更多的是一种动机,当你想做一些复杂的事情时,你应该寻找什么。

为什么你想分配
buf
然后通过将
buf
指向其他东西,立即扔掉指向分配内存的指针?链接问题(您分配的任何指针,取消分配)的一般原则是成立的,但在这里,您不想分配它,也不需要取消它。@wyphan不。几乎完全是错误的方法。C_Loc(val)表示意图(In),buf表示意图(Out)。因此,在调用之前与buf关联的任何内存都将丢失。“这是否意味着我在调用分配的指针数组上的
C\u F\u POINTER()
时就创建了内存泄漏?”是的,正是这样。
buf
形成
[sz\u buf]
之后
c\u f\u指针
调用:这就是shape参数的作用。您不需要首先分配
buf
:它使用
val
已经具有假定大小而不是假定秩的内存(序列)。假设大小的实现早于我使用Fortran的时间,您不想知道这需要多长时间!有趣的是,我甚至没有意识到使用自动阵列是可能的!但是编译器是否足够聪明,可以对数组切片执行零拷贝呢?另一方面,我认为如果我想编写处理复杂数据类型的类似HDF5子例程,仍然需要C指针技巧,因为HDF5本身并不支持它们。我在考虑C++中的代码> double double复合> >空白*> >双*<代码> >使用<代码> cffpPOTIN()/<代码>,或者类似于。除非我想变得邋遢,把
REAL
COMPLEX
类型混在一起。。。我知道GFortran 10对此不满意。
d
不是一个自动数组(因为它是一个伪数组)。只要(编译器)知道实际参数数组(整个或部分)是连续的,它就应该避免为参数传递执行任何复制入/复制出操作。简单的连续字符(如整个数组
a
和节
a(:,:,:,1)
)的设计是为了让编译器能够做到这一点。另外,从什么时候开始,
[
]
字符是Fortran标准的一部分?这比20年前的
(/
/)
好看多了。
  implicit none

  integer :: a(2,2,2,2), b(4,2,2), c(4,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