Я хотел бы расширить выделяемый атрибут структуры, и MOVE_ALLOC()
кажется самым чистым способом сделать это. Поэтому я создал подпрограмму, используя Pointer, Intent(in)
, указывающий на структуру в качестве аргумента, и попытался вызвать:
Type(STRUCT1), Pointer, Intent(in) :: str1
...
call MOVE_ALLOC(TO= str1%arrayofint , FROM= temparray)
, где str1
- указатель на структуру, а arrayofint
- атрибут, который должен быть расширен , Смотрите подпрограмму LOC_extendsecond()
следующего примера кода. Компилятор ifort возвращает следующую ошибку:
Source1.f90(91): error #7999: The FROM or TO arguments of a MOVE_ALLOC reference must not be INTENT(IN). [MOVE_ALLOC]
Как будто str1%arrayofint
были Intent(in)
. Помня, что указатель str1
равен Intent(in)
, являются ли атрибуты остроконечной структуры str1%arrayofint
, которые следует рассматривать как Intent(in)
?
Чтобы исследовать проблему, я попытался не использовать MOVE_AllOC()
и обнаружил, что освобождение или выделение str1%arrayofint
в подпрограмме не вызывает никаких ошибок или предупреждений от ifort. Смотрите подпрограмму LOC_extendfirst()
примера кода.
Мой коллега предложил обходной путь (спасибо Лу c!): Создана локальная копия указателя, и можно вызывать MOVE_AllOC()
, используя эту локальную копию указателя, без вызова ifort ошибка. См. Подпрограмму LOC_extendthird()
примера кода.
Type(STRUCT1), Pointer, Intent(in) :: str1
Type(STRUCT1), Pointer :: str2
str2=>str1
...
call MOVE_ALLOC(TO= str2%arrayofint , FROM= temparray)
Вот пример кода:
Module Source1
Implicit None
Public :: STRUCT1
Private
Type STRUCT1
Integer, dimension(:), allocatable :: arrayofint
End Type STRUCT1
Contains
Subroutine newstruct1(str1,ier,errmsg)
Type(STRUCT1), Pointer, Intent(inout) :: str1
Integer, Intent(out) :: ier
character(len=256), Intent(out) :: errmsg
ier=0
allocate(str1,stat=ier, errmsg=errmsg)
if( ier>0) return
allocate(str1%arrayofint(2),stat=ier, errmsg=errmsg)
if( ier>0) return
End Subroutine newstruct1
Subroutine LOC_extendfirst(str1,targetsize,ier,errmsg)
Type(STRUCT1), Pointer, Intent(in) :: str1
Integer, Intent(out) :: ier
character(len=256), Intent(out) :: errmsg
Integer, Intent(in) :: targetsize
Integer,dimension(1) :: shp
Integer :: newsize , formersize
Integer, dimension(:), allocatable :: temparray
ier=0
shp=shape(str1%arrayofint)
formersize=shp(1)
if (targetsize .GT. formersize) then
newsize=MAX(targetsize,2*formersize)
allocate(temparray(newsize),stat=ier, errmsg=errmsg)
if( ier>0) then; return ; endif
temparray(1:formersize)=str1%arrayofint
allocate(temparray(formersize),stat=ier, errmsg=errmsg)
if( ier>0) then; return ; endif
temparray=str1%arrayofint
if(allocated(str1%arrayofint)) deallocate(str1%arrayofint)
allocate(str1%arrayofint(newsize),stat=ier, errmsg=errmsg)
if( ier>0) then; return ; endif
str1%arrayofint(1:formersize)=temparray
if(allocated(temparray)) deallocate(temparray)
endif
End Subroutine LOC_extendfirst
Subroutine LOC_extendsecond(str1,targetsize,ier,errmsg)
Type(STRUCT1), Pointer, Intent(in) :: str1
Integer, Intent(out) :: ier
character(len=256), Intent(out) :: errmsg
Integer, Intent(in) :: targetsize
Integer,dimension(1) :: shp
Integer :: newsize , formersize
Integer, dimension(:), allocatable :: temparray
ier=0
shp=shape(str1%arrayofint)
formersize=shp(1)
if (targetsize .GT. formersize) then
newsize=MAX(targetsize,2*formersize)
allocate(temparray(newsize),stat=ier, errmsg=errmsg)
if( ier>0) then; return ; endif
temparray(1:formersize)=str1%arrayofint
! TODO uncomment the following line to get error from ifort
call MOVE_ALLOC(TO= str1%arrayofint , FROM= temparray)
endif
End Subroutine LOC_extendsecond
Subroutine LOC_extendthird(str1,targetsize,ier,errmsg)
Type(STRUCT1), Pointer, Intent(in) :: str1
Integer, Intent(out) :: ier
character(len=256), Intent(out) :: errmsg
Integer, Intent(in) :: targetsize
Integer,dimension(1) :: shp
Integer :: newsize , formersize
Integer, dimension(:), allocatable :: temparray
Type(STRUCT1), Pointer :: str2
ier=0
str2=>str1
shp=shape(str2%arrayofint)
formersize=shp(1)
if (targetsize .GT. formersize) then
newsize=MAX(targetsize,2*formersize)
allocate(temparray(newsize),stat=ier, errmsg=errmsg)
if( ier>0) then; return ; endif
temparray(1:formersize)=str1%arrayofint
call MOVE_ALLOC(TO= str2%arrayofint , FROM= temparray)
endif
End Subroutine LOC_extendthird
End Module Source1
Вызов ifort 19.0.2.190 IA32 на windows с использованием ifort /nologo /debug:full /Od /debug-parameters:all /warn:unused /warn:truncated_source /warn:uncalled /warn:interfaces /Qsave /traceback /check:pointer /check:bounds /check:uninit /libs:static /threads /dbglibs /c /Qm32 "Source1.f90"
производит ошибка.
Наоборот, использование gfortran из g cc 6.3.0 на Debian с использованием gfortran -c Source1.f90 -Wall
не приводит к ошибке: отображает только предупреждения о функции not используется.
Я довольно новичок ie относительно Фортрана. Я знаю, что указатели Fortran обертывают гораздо больше данных, чем указатель C, поэтому мне интересно, корректно ли изменение атрибута str1%arrayofint
, поскольку str1
является Pointer, Intent(in)
, точно так же, как изменение str1-> arrayofint в функции правильно Указатель str1 передается по значению.
Как устранить разницу в поведении между ифортом и гфортраном? Является ли ifort правильным, поскольку он сообщает об ошибке в данной ситуации? Почему ifort считает str1%arrayofint
Intent(in)
, как если бы str1
было Type(STRUCT1), Intent(in)
, а не Type(STRUCT1), Pointer, Intent(in)
? Является ли введение локальной копии указателя, как показано в LOC_extendthird()
, наиболее подходящим способом смягчения проблемы?