Передача определяемого пользователем типа данных в массиве
Я могу определить пользовательский тип данных с размещаемым массивом в качестве его типа данных.
Распределение работает отлично, пока мы все еще в той же подпрограмме. Но я не знаю, как передать этот тип пользовательского типа данных в качестве аргумента подпрограммы.
Компилятор Intel показывает ошибку # 6530
:
"Error 1 error #6530: The array spec for this component must be of explicit shape and each bound must be an initialization expression."
Код был предоставлен ниже, чтобы показать ошибку. Он написан на Фортране 77. Я работаю на Фортране 77, так как мне придется добавить этот код в подпрограмму пользователя Abaqus, которая принимает только файлы Фортрана 77.
PROGRAM DERIVED_DATA_TYPE_CHECK
IMPLICIT NONE
INTEGER :: I,J,A,B
TYPE SS
SEQUENCE
DOUBLE PRECISION, DIMENSION(:,:), ALLOCATABLE :: S1
END TYPE SS
TYPE (SS),DIMENSION(:,:),ALLOCATABLE :: SS_
A=10
B=10
ALLOCATE (SS_(A,B))
! ALLOCATING THE VARIABLE S1 DIMENSIONS
! EVERY ALLOCATABLE VARIABLE HAS THE SAME SIZE AS
! THE TOTAL NUMBER OF STRUCTURE (TYPE)
DO I = 1,A
DO J = 1,B
ALLOCATE(SS_(I,J)%S1(A,B))
ENDDO
ENDDO
CALL PASS_ARG(SS_,A,B)
END
SUBROUTINE PASS_ARG(SS_,A,B)
IMPLICIT NONE
INTEGER :: A,B
TYPE SS
SEQUENCE
DOUBLE PRECISION, DIMENSION(A,B) :: S1
END TYPE SS
TYPE (SS), DIMENSION (A,B) :: SS_
END
Программа при компиляции выдает ошибку, как показано ниже:
----------
Error 2 error #6530: The array spec for this component must be of explicit shape and each bound must be an initialization expression. [S1]
----------
Должен быть способ решить эту проблему. Я хочу держаться подальше от обычных блоков или модулей. Во всяком случае, я не могу использовать модуль в Фортране.
Чтобы избежать этой ошибки, я использовал выделяемые переменные в основной программе, а также вызывал подпрограмму. Затем программа компилируется, но при выполнении выдает ошибку "выделение выполнено более одного раза".
Наконец я думаю, что мне придется использовать некоторые глобальные константы..... Я думаю.
1 ответ
Вы можете делать то, что хотите, без модулей, но это не значит, что вы должны это делать. Но сначала давайте посмотрим, на что жалуется компилятор.
Рассмотрим определение производного типа
type t
real x(i)
end type
Этот тип имеет компонент массива x
(с привязкой i
); это массив явной формы. В таком случае связанная i
должно быть выражением спецификации. Здесь это, по сути, означает, что i
должен быть константой.
В подпрограмме pass_arg
вопроса, границы компонента - это не константы, а фиктивные аргументы. Вот почему компилятор жалуется.
Чтобы решить эту проблему, вы должны снова сделать компонент в типе подпрограммы выделяемым. Вам тогда даже не нужно проходить a
а также b
: границы будут доступны из статуса размещения массива.
Теперь вы говорите, что хотите сделать это без использования модулей. С исправлением выше, это то, что вы можете сделать. Однако я настоятельно советую этого не делать: это работает только потому, что производный тип является типом последовательности. Использование типа последовательности является ограничивающим и подверженным ошибкам:
- типы последовательностей ограничены в том, какими могут быть их компоненты, и не могут иметь привязанных к типу процедур;
- вы должны точно повторять определение типа в каждом месте, где оно используется;
- Вы не можете иметь частные компоненты в типе.
Гораздо лучше создать модуль и один раз определить производный тип (и сделать его непоследовательным типом).
Второй вариант для примера вопроса заключается в использовании параметризованного производного типа:
type ss(a,b)
type, len :: a, b
! Not a sequence type, define once in a module
double precision, dimension(a,b) :: s1
end type
В основной программе это можно использовать как (используя именованные константы для ясности)
use mod_with_type_ss
implicit none
integer, parameter :: a=10, b=10
type(ss(a,b)) ss_(a,b)
call pass_arg(ss)
end
Тогда подпрограмма может быть
subroutine pass_arg(ss_)
use mod_with_type_ss
type(ss(*,*)), intent(in) :: ss_ ! The type parameters are assumed
...
end subroutine