Pointers Fortran 90 compaq visual Fortran与gfortran之间的差异

Pointers Fortran 90 compaq visual Fortran与gfortran之间的差异,pointers,memory-management,fortran,fortran90,gfortran,Pointers,Memory Management,Fortran,Fortran90,Gfortran,这可能是一个特定的问题,但我认为它与这两个编译器(Compaq visual Fortran优化编译器版本6.5和minGW)如何处理内存有关。我试图了解在Fortran 90中使用指针的最佳实践(我必须使用指针)。下面是一个示例代码,它应该“开箱即用”,gfortran编译器会发出一条警告:“指针值函数出现在赋值的RHS上”,而另一个编译器不会发出警告 module vectorField_mod implicit none type vecField1D pri

这可能是一个特定的问题,但我认为它与这两个编译器(Compaq visual Fortran优化编译器版本6.5和minGW)如何处理内存有关。我试图了解在Fortran 90中使用指针的最佳实践(我必须使用指针)。下面是一个示例代码,它应该“开箱即用”,gfortran编译器会发出一条警告:“指针值函数出现在赋值的RHS上”,而另一个编译器不会发出警告

   module vectorField_mod
   implicit none

   type vecField1D
     private
     real(8),dimension(:),pointer :: x
     logical :: TFx = .false.
   end type

   contains

   subroutine setX(this,x)
     implicit none
     type(vecField1D),intent(inout) :: this
     real(8),dimension(:),target :: x
     logical,save :: first_entry = .true.
     if (first_entry) nullify(this%x); first_entry = .false.
     if (associated(this%x)) deallocate(this%x)
     allocate(this%x(size(x)))
     this%x = x
     this%TFx = .true.
   end subroutine

   function getX(this) result(res)
     implicit none
     real(8),dimension(:),pointer :: res
     type(vecField1D),intent(in) :: this
     logical,save :: first_entry = .true.
     if (first_entry) nullify(res); first_entry = .false.
     if (associated(res)) deallocate(res)
     allocate(res(size(this%x)))
     if (this%TFx) then
       res = this%x
     endif
   end function

   end module

   program test
   use vectorField_mod
   implicit none

   integer,parameter :: Nx = 15000
   integer :: i
   real(8),dimension(Nx) :: f
   type(vecField1D) :: f1

   do i=1,10**4
     f = i
     call setX(f1,f)
     f = getX(f1)
     call setX(f1,f)
     if (mod(i,5000).eq.1) then
       write(*,*) 'i = ',i,f(1)
     endif
   enddo
   end program
此程序在两个编译器中都运行。但是,将循环从10**4更改为10**5会导致gfortran出现严重的内存问题

使用CTR-ALT-DLT并打开“性能”,在gfortran中运行时,物理内存会快速增加,而康柏编译器似乎不会移动。我通常在我的电脑崩溃前取消,所以我不确定它达到最大值后的行为

这似乎不是使用指针的合适方式(我在派生数据类型中需要指针)。所以我的问题是:如何在维护相同类型的接口和功能的同时安全地使用指针

p、 我知道主程序似乎没有做任何建设性的事情,但重点是我不认为循环应该受到内存的限制,而是应该是运行时的函数


非常感谢您的帮助。

此代码有一些问题,可能是由于对语言的误解造成的。这些问题与特定的编译器无关-代码本身已损坏

从概念上讲,请注意:

  • 在Fortran 90中,每个程序的过程中都有一个且只有一个已保存变量的实例
  • 每次调用函数时,表示函数结果的变量总是以未定义开头
  • 如果希望调用范围中的指针指向具有指针结果的函数的结果,则必须使用指针赋值
  • 如果分配了指针,则需要进行匹配的取消分配
存在一个潜在的逻辑错误,即
getX
setX
过程中保存的
first_条目
变量与
setX
过程中的对象特定状态和
getX
过程中的过程实例特定状态合并

第一次调用
setX
时,特定
对象的
x
指针组件将由于if语句而无效(这里也存在样式不好的问题-注意if语句后面有多个语句-只有第一个语句受条件约束!)。如果使用不同的
this
再次调用
setX
,则第一个条目将被设置为false,并且
this
对象将无法正确设置。我怀疑您应该测试
这个%TFX

类似地,第一次调用
getX
,否则未定义的函数结果变量
res
将为空。但是,在所有后续调用中,函数结果都不会为null(函数结果在每次执行函数时都是未定义的),然后会错误地用于相关测试,也可能错误地用于deallocate语句。(在具有未定义关联状态的指针上调用associated(或解除分配)是非法的-请注意,未定义关联状态与Dis离状态不同。)

getX
返回一个指针结果-由分配的指针创建的结果。该指针随后丢失,因为“正常”赋值用于访问函数求值结果的值。由于此指针丢失,因此不能(因此也没有…)使用匹配的deallocate语句来反转指针分配。因此,程序会泄漏内存。几乎可以肯定的是,在主程序中捕获getX函数值的东西(
f
在本例中,但是
f
用于多个东西,所以我将其称为
f_ptr
…)本身应该是指针,并且应该是指针赋值-
f_ptr=>getX(f1)
。在随后的setX调用和写入语句中使用了
f_ptr
的值之后,就可以显式地释放它

不鼓励使用具有指针结果的函数的原因之一是,当打算进行指针赋值时,可能会意外使用正常赋值。如果需要返回指针,那么使用子例程

Fortran 95允许指针组件的默认初始化为NULL,从而简化了指针组件的管理。(请注意,您在类型定义中使用的是默认初始化,因此您的代码不是Fortran 90!)

Fortran 2003(或Fortran 95+可分配TR-这是大多数维护的编译器支持的语言级别)引入了可分配函数结果-这消除了许多使用指针函数可能产生的潜在错误


Fortran 95+可分配TR支持现在非常普遍,在这一点上所做的语言改进和修复非常有用(除非您在某种模糊的平台上操作),将语言级别限制在Fortran 90是非常荒谬的。

很抱歉,我没有接受您在上一个问题中的回答,这显然非常相似。谢谢你的坚持。这些注释很有意义,现在,我认为我将坚持使用子例程返回指针。另外,我将删除第一个保存的变量,因为我认为它对我的情况没有帮助。我认为,由于我正在使用的数据结构,需要在更高的级别上进行取消和删除。再次感谢你