Fortran 派生类型包含可从 C 访问的派生类型

Fortran derived types containing derived types to be accessible from C

作为此 的扩展,我有派生类型,它们本身具有派生类型作为成员。示例如下:

module simple
use  iso_c_binding

TYPE SIMPLEF
  INTEGER :: A
  INTEGER, POINTER :: B, C(:)
END TYPE SIMPLEF

TYPE COMPLEXF
  INTEGER :: X
  TYPE (SIMPLEF) :: Y
END TYPE COMPLEXF
end module simple

与上面的 post 一样,目标是在 C 中具有相似的派生类型,并能够将值来回传递给 Fortran。解决方案可见。但是这里它不仅仅是一个派生类型,它是一个派生类型,其成员本身就是派生类型。我是否需要为 COMPLEXF 创建 Y 的每个成员的子例程,即 SETY_A、QUERYY_A、SETY_B、QUERYY_BSIZE、SQUERYY_B 等?还是有更好的方法来解决这个问题?

可以使用相同的方法。什么是最好的取决于您认为什么是 C 客户端与 Fortran 对象交互的最佳方式。在编写太多代码之前,应该对此进行一些思考。

如前所述,y 组件的存在是 C 代码可能不需要关心的细节 - 而不是调用过程 sety_a,您可以将其命名为 set_a.

如果要对 COMPLEXF 类型的组件进行许多操作并且您想避免间接级别,或者如果有许多相同的 COMPLEXF 组件类型,那么您可以使用与该组件对应的子对象的 C 地址作为不透明句柄。

例如,更改 中的 GetHandleReleaseHandle 过程以使用 COMPLEXF 类型作为顶级类型(即- 将 COMPLEXF 替换为该答案中出现的所有 SIMPLEF)。然后,您可以按照以下行编写 QueryYHandle 过程或类似过程:

FUNCTION QueryYHandle(handle) RESULT(y_handle)
  TYPE(C_PTR), INTENT(IN), VALUE :: handle
  TYPE(C_PTR) :: y_handle
  TYPE(COMPLEXF), POINTER :: p
  !***
  CALL C_F_POINTER(handle, p)
  y_handle = C_LOC(p%y)
END FUNCTION QueryYHandle

现在您可以直接使用 SIMPLEF 子对象的句柄 - 使用与链接答案中完全相同的 Query*/Set* 过程。

在这种情况下,不需要编写程序来释放 y_handle 指定的对象,因为与 y 组件关联的子对象的生命周期由 y 组件的生命周期决定具有该子对象的对象 - 当调用 COMPLEXF 超级对象的 ReleaseHandle 时,该子对象将消失。

请注意,如上所述,对于在语言之间传递错误类型的句柄(例如,如果 C 代码不小心调用了一个旨在与 COMPLEXF 句柄实际上是 SIMPLEF 对象的句柄)。如果这是有问题的,那么可以添加保护,可能是通过将句柄类型与用作不透明句柄的对象中的 C 地址捆绑在一起,并在尝试将 Fortran 指针与 C 地址指定的对象相关联之前检查该句柄类型。