Pointers Ifort:move_alloc()在指针的属性上,intent(in)触发错误
我想扩展结构的可分配属性,这似乎是最干净的方法。因此,我使用指向结构作为参数的Pointers Ifort:move_alloc()在指针的属性上,intent(in)触发错误,pointers,memory-management,compiler-errors,fortran,Pointers,Memory Management,Compiler Errors,Fortran,我想扩展结构的可分配属性,这似乎是最干净的方法。因此,我使用指向结构作为参数的指针Intent(in)创建了一个例程,并尝试调用: Type(STRUCT1), Pointer, Intent(in) :: str1 ... call MOVE_ALLOC(TO= str1%arrayofint , FROM= temparray) 其中,str1是指向结构的指针,ArrayFint是要扩展的属性。请参阅以下示例代码的子程序LOC_extendsecond()编译器ifort返回以下错误:
指针Intent(in)
创建了一个例程,并尝试调用:
Type(STRUCT1), Pointer, Intent(in) :: str1
...
call MOVE_ALLOC(TO= str1%arrayofint , FROM= temparray)
其中,str1
是指向结构的指针,ArrayFint
是要扩展的属性。请参阅以下示例代码的子程序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%arrayFint是Intent(in)
请记住,指针str1
是Intent(in)
,指针结构str1%arrayFint
的属性是否被视为Intent(in)
?
为了调查该问题,我尝试不使用MOVE_AllOC()
,并发现在例程中取消分配或分配str1%arrayFint
,不会触发ifort的任何错误或警告。请参阅示例代码的子例程LOC_extendedfirst()
我的一位同事建议了一种解决方法(谢谢Luc!):创建指针的本地副本,并且可以使用指针的本地副本调用MOVE\u AllOC()
,而不会引发错误。请参阅示例代码的子例程LOC\u extendedthird()
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
在windows上调用ifort 19.0.2.190 IA32,使用ifort/nologo/debug:full/Od/debug参数:all/warn:unused/warn:truncated\u source/warn:uncalled/warn:interfaces/Qsave/traceback/check:pointer/check:bounds/check:uninit/libs:static/threads/dbglibs/c/Qm32“Source1.f90”
会产生错误
相反,使用gfortran-c Source1.f90-Wall在Debian上使用gcc 6.3.0中的gfortran不会导致任何错误:
它只显示未使用函数的警告
关于Fortran,我是个新手。我知道Fortran指针封装的数据比C指针多得多,所以我想知道修改属性str1%arrayFint
是否正确,因为str1
是指针,Intent(in)
,就像在函数中修改str1->arrayFint是正确的,因为指针str1是通过值传递的
如何解决ifort和gfortran之间的行为差异?ifort报告当前情况下的错误是否正确?为什么ifort认为str1%arrayFint是
Intent(in)
,好像str1是类型(STRUCT1)、Intent(in)
而不是类型(STRUCT1)、指针、Intent(in)
?如LOC\u extendthird()
中所示引入指针的本地副本是否是缓解该问题的最合适方法?对于指针伪参数,intent(in)
属性意味着指针不应出现在所谓的指针关联上下文中。不严格地说,这意味着不允许(潜在地)更改伪参数的指针关联。允许您更改此指针目标的值
对于指针伪参数,
intent(in)
属性不会“级联”到参数的子对象(例如在本例中的组件arrayofint
):str1目标的组件arrayofint
没有intent(in)
属性
在类似于带有指针的str1%arrayFint
的引用中,这是对str1
目标的组件arrayFint
的引用。即使intent(in)
属性确实应用于指针伪参数的子对象,str1%arrayofint
引用的对象也不是str1
的子对象
ifort认为这样的对象具有intent(in)
属性是错误的。您已经找到了一种有效的方法来解决ifort中的这些缺点。你应该考虑把这个缺陷报告给英特尔。< /P>
最后,也许有更好的方法来解决你的问题,在不使用指针哑参数的情况下调整组件的大小,但是我不会考虑这个答案。
对代码的无关紧要的评论:返回;endif可以替换为if(ier>0)return
,即您可以使用一行if
语句,而不使用then
或end if
。使用intent(in)
属性,您可以“承诺”只使用数据,而不更改它-请参阅。将其更改为intent(inout)
(默认的intent属性)应该可以解决此问题。感谢@HighPerformanceMark的反馈。在原始代码中,如果出现错误,则在返回之前调用其他例程。谢谢@jcerar:事实上,修改为Intent(inout)可以解决问题,但该例程在其他例程中调用,因此其他例程将被修改为Intent(inout),从而使代码越来越不可读。此外,据我所知,我履行了我的承诺:我不会在重新分配pointed结构的属性时更改指针str1
。鉴于我在Fortran指针方面的经验有限,上一句可能最终被证明是错误的…@jcerar,使用intent(in)
伪参数,您并没有承诺不更改数据:您只是承诺不更改指针关联。感谢@francescalus的回答。我真的需要一个有经验的fortran开发人员的观点,因为我的fortran实践并没有让质疑编译器的正确性看起来是明智的。根据您的建议,我将此问题发布在上。请随时向我们通报英特尔的任何结论。是的,当然!到目前为止,史蒂夫·莱昂内尔的观点与你的一致:ifort存在问题。他引用fortran标准(8.5.10p6):如果非指针对象有意图