在派生类型中使用可分配的目标变量

Posted

技术标签:

【中文标题】在派生类型中使用可分配的目标变量【英文标题】:Using allocatable, target variables in a derived type 【发布时间】:2013-06-14 18:14:33 【问题描述】:

我正在将 Fortran 代码与 C dll 绑定,并且我想要一个可与 C 互操作的 Fortran 数组。我目前有以下子例程将 Fortran 数组与 C double* 绑定:

SUBROUTINE Pack_Inputs( Input , In_X )
  TYPE( InputType ) ,               INTENT(INOUT)            :: Input
  REAL(KIND=C_DOUBLE) , ALLOCATABLE , TARGET , INTENT(INOUT) :: In_X(:)

  IF ( .NOT. ALLOCATED(In_X)     ) ALLOCATE( In_X    (Input%Xlen)     )

  DO i = 1,Input%C_obj%Xlen       
     In_X(i) = Input%X(i)
  END DO
  Input%C_obj%X = C_LOC(In_X)    
END SUBROUTINE Pack_Inputs

然而,我不喜欢当前代码的地方在于,我不断分配内存,并且在输入 C dll 时不得不解压数组(部分原因是我不愿意在 @ 上使用 SAVE 属性) 987654323@)。我宁愿在 Fortran 派生类型中声明一次 In_X。这导致了这篇文章的动机。在这个派生类型中:

USE , INSTRINSIC :: ISO_C_BINDING

TYPE , PUBLIC  :: InputType                               
   TYPE(InputType_C)                          :: C_obj   
   REAL(KIND=C_DOUBLE) , ALLOCATABLE , TARGET :: In_X(:)   
   REAL    , DIMENSION(:) , ALLOCATABLE       :: X                    
   REAL    , DIMENSION(:) , ALLOCATABLE       :: Y                    
   REAL    , DIMENSION(:) , ALLOCATABLE       :: Z                    
   INTEGER , DIMENSION(:) , ALLOCATABLE       :: index
   INTEGER                                    :: Xlen                 
   INTEGER                                    :: Ylen                 
   INTEGER                                    :: Zlen                 
   INTEGER                                    :: indexlen
END TYPE InputType     

我得到错误:

REAL(KIND=C_DOUBLE) , ALLOCATABLE  , TARGET :: In_X(:)
                                          1
    Error: Attribute at (1) is not allowed in a TYPE definition

有没有办法消除这个错误?

【问题讨论】:

【参考方案1】:

我以前遇到过这个问题,对我有用的解决方案是将组件声明为POINTER 而不是ALLOCATABLE, TARGET。我不确定 Fortran 标准是否不支持它,或者编译器没有实现此功能。我使用的是ifort v12.0.2.137

这对您来说是一个可以接受的解决方案吗?然后您就可以将其用作指针目标。

TYPE , PUBLIC  :: InputType                               
   TYPE(InputType_C)                          :: C_obj   
   REAL(KIND=C_DOUBLE),DIMENSION(:),POINTER   :: In_X => NULL()
   REAL    , DIMENSION(:) , ALLOCATABLE       :: X                    
   REAL    , DIMENSION(:) , ALLOCATABLE       :: Y                    
   REAL    , DIMENSION(:) , ALLOCATABLE       :: Z                    
   INTEGER , DIMENSION(:) , ALLOCATABLE       :: index
   INTEGER                                    :: Xlen                 
   INTEGER                                    :: Ylen                 
   INTEGER                                    :: Zlen                 
   INTEGER                                    :: indexlen
END TYPE InputType

然后,您可以将In_X 指针与目标数据相关联:

In_X(1:Input%C_obj%Xlen) => Input%X(1:Input%C_obj%Xlen)

请注意,Input%X 还需要有一个 TARGET 属性。

【讨论】:

也许,但也许我没有正确应用它。我收到错误:IF ( .NOT. ALLOCATED(In_X) ) ALLOCATE( In_X (Input%Xlen) ) Error: 'array' argument of 'allocated' intrinsic at (1) must be ALLOCATABLE 谢谢!您的回答提供了灵感,尽管我采用了稍微不同的方法,因为我在初始化时在 C 中声明了大小和数组内容,因为我使用的是 C_F_POINTER(...)。您关于REAL(KIND=C_DOUBLE),DIMENSION(:),POINTER :: In_X => NULL() 的注释确实帮助我走上了正轨。 标准不支持。整个类型的实例必须声明为目标。

以上是关于在派生类型中使用可分配的目标变量的主要内容,如果未能解决你的问题,请参考以下文章

在 TypeScript 中为具有类型变量的抽象类中的派生类分配泛型类型

指向包含可分配数组的派生类型的指针

派生类型中的可变长度数组

C++ 类型将基础对象转换为派生对象

Fortran - 可分配派生类型的可分配数组

检测基类对指向派生类的引用的分配