1

Я связываю код Fortran с C dll, и я хотел бы иметь массив Fortran, взаимодействующий с C. В настоящее время я имею следующую подпрограмму для связывания массива Fortran с с двойной *:Использование allocatable, целевые переменные в производном типе

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 

Однако то, что я не люблю о текущем коде является то, что я постоянно выделения памяти, и того, чтобы распаковать массив, когда DLL C вводится (частично обусловлен моим нежеланием для использования атрибута SAVE на In_X(:)). Я предпочел бы много объявить In_X один раз, внутри производного типа Fortran. Это приводит к мотивации для этой должности. В этом производном типе:

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 атрибут, а также.

+0

Возможно, но, возможно, я не применяю его правильно. Я получаю ошибку: 'IF (.NOT. ALLOCATED (In_X)) ALLOCATE (In_X (Input% Xlen)) Ошибка: аргумент 'array' 'присвоенный' intrinsic в (1) должен быть ALLOCATABLE' –

+0

@ user1628622 OK, см. мое редактирование выше. – milancurcic

+0

Спасибо! Ваш ответ дал вдохновение, хотя я принял несколько иной подход, поскольку я использую 'C_F_POINTER (...)', так как я объявляю содержимое размера и массива в C при инициализации. Ваша заметка о 'REAL (KIND = C_DOUBLE), DIMENSION (:), POINTER :: In_X => NULL()' помогла мне правильно подняться. –