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

时间:2023-02-04 21:40:58

As an extension to this post, I have derived types which have as members derived types themselves. Example below:

作为这篇文章的扩展,我已经派生出了具有成员派生类型的类型。示例如下:

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

The aim is, as in the post above, to have similar derived types in C and to be able to pass values back and forth to Fortran. The solution can be seen here. However here it's not just a derived type, it is a derived type with a member which is a derived type itself. Would I need to create for COMPLEXF, subroutines for each member of Y, i.e. SETY_A, QUERYY_A, SETY_B, QUERYY_BSIZE, SQUERYY_B etc.? Or is there a better way to approach this?

如上文所述,目标是在C中具有类似的派生类型,并且能够将值来回传递给Fortran。解决方案可以在这里看到。然而,这里它不仅仅是一个派生类型,它是一个派生类型,其成员本身就是派生类型。我是否需要为每个Y成员创建COMPLEXF子程序,即SETY_A,QUERYY_A,SETY_B,QUERYY_BSIZE,SQUERYY_B等?或者有更好的方法来解决这个问题吗?

1 个解决方案

#1


2  

The same approach can be used. What's best depends on what you think is the best way for your C clients to interact with your Fortran objects. Some thought should be put into this before you write too much code.

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

As presented, the existence of the y component is a detail that the C code probably doesn't need to care about - rather than calling the procedure sety_a you could just name it set_a.

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

If there are going to be many operations on the component of the COMPLEXF type and you want to avoid a level of indirection, or if there are many such components of COMPLEXF of the same type, then you can use the C address of the subobject that corresponds to that component as an opaque handle.

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

For the sake of example, alter the GetHandle and ReleaseHandle procedures in the linked answer to work with the COMPLEXF type as the top level type (that is - substitute COMPLEXF for all the appearances of SIMPLEF in that answer). You could then write a QueryYHandle procedure or similar, along the lines of:

例如,更改链接答案中的GetHandle和ReleaseHandle过程以使用COMPLEXF类型作为*类型(即 - 在该答案中替换所有SIMPLEF外观的COMPLEXF)。然后你可以编写一个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

Now you can work with the handle to the SIMPLEF subobject directly - using the exact same Query*/Set* procedures as in the linked answer.

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

There's no need to write a procedure to deallocate the object nominated by the y_handle in this case, because the lifetime of the subobject associated with the y component is determined by the lifetime of the object that has that subobject - that subobject will go away when ReleaseHandle for the COMPLEXF super-object is called.

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

Note that there are no protections in the approach, as outlined above, for the wrong sort of handle to be passed between languages (for example - if the C code accidentally called a procedure intended to work with a COMPLEXF handle with a handle that was actually for a SIMPLEF object). If that is problematic then protections can be added, perhaps by bundling a handle type in with the C address in the object used as the opaque handle and checking that handle type before attempting to associate a Fortran pointer with the object nominated by the C address.

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

#1


2  

The same approach can be used. What's best depends on what you think is the best way for your C clients to interact with your Fortran objects. Some thought should be put into this before you write too much code.

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

As presented, the existence of the y component is a detail that the C code probably doesn't need to care about - rather than calling the procedure sety_a you could just name it set_a.

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

If there are going to be many operations on the component of the COMPLEXF type and you want to avoid a level of indirection, or if there are many such components of COMPLEXF of the same type, then you can use the C address of the subobject that corresponds to that component as an opaque handle.

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

For the sake of example, alter the GetHandle and ReleaseHandle procedures in the linked answer to work with the COMPLEXF type as the top level type (that is - substitute COMPLEXF for all the appearances of SIMPLEF in that answer). You could then write a QueryYHandle procedure or similar, along the lines of:

例如,更改链接答案中的GetHandle和ReleaseHandle过程以使用COMPLEXF类型作为*类型(即 - 在该答案中替换所有SIMPLEF外观的COMPLEXF)。然后你可以编写一个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

Now you can work with the handle to the SIMPLEF subobject directly - using the exact same Query*/Set* procedures as in the linked answer.

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

There's no need to write a procedure to deallocate the object nominated by the y_handle in this case, because the lifetime of the subobject associated with the y component is determined by the lifetime of the object that has that subobject - that subobject will go away when ReleaseHandle for the COMPLEXF super-object is called.

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

Note that there are no protections in the approach, as outlined above, for the wrong sort of handle to be passed between languages (for example - if the C code accidentally called a procedure intended to work with a COMPLEXF handle with a handle that was actually for a SIMPLEF object). If that is problematic then protections can be added, perhaps by bundling a handle type in with the C address in the object used as the opaque handle and checking that handle type before attempting to associate a Fortran pointer with the object nominated by the C address.

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