康柏视觉fortran和gfortran之间的Fortran 90差异 [英] Fortran 90 difference between compaq visual fortran and gfortran

查看:292
本文介绍了康柏视觉fortran和gfortran之间的Fortran 90差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能是一个具体问题,但我认为它与这两种编译器(Compaq visual Fortran Optimizing Compiler Version 6.5和minGW)如何处理内存有关。我想了解在Fortran 90中使用指针的最佳做法(我必须使用它)。下面是一个示例代码,它应该可以通过gfortran编译器的一个警告开箱即用:赋值函数出现在赋值的RHS上,并且没有其他编译器的警告。

 模块vectorField_mod 
隐式无

类型vecField1D
私有
real(8),dimension( :),指针:: x
logical :: TFx = .false。
结束类型

包含

子程序setX(this,x)
隐式无
类型(vecField1D),intent(inout): :这个
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。
结束子程序

函数getX(this)结果(res)
隐式无
real(8),dimension(:),pointer :: res
类型(vecField1D),intent(in):: this
logical,save :: first_entry = .true。
if(first_entry)nullify(res); first_entry = .false。如果(这个%TFx)然后
res =这个%(b)如果(关联(res))释放(res)
分配(res(size(this%x))

, x
endif
结束函数

结束模块

程序测试
使用vectorField_mod
隐式无

integer,parameter :: Nx = 15000
integer :: i
real(8),dimension(Nx):: f
类型(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
结束程序

这个程序在两个编译器中运行。但是,将循环从10 ** 4更改为10 ** 5会导致gfortran严重的内存问题。

使用CTR-ALT-DLT并打开性能,在gfortran中运行时物理内存会迅速增加,而且对于compaq编译器来说似乎没有什么变化。我通常在我的电脑崩溃之前取消,所以我不确定它达到最大值后的行为。



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



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



非常感谢任何帮助。

解决方案

这段代码有一些问题,也许由语言周围的误解造成的。这些问题与特定编译器无关 - 代码本身已被破坏。

从概念上讲,请注意:




  • 在Fortran 90的每个程序中,程序中保存的变量有且仅有一个实例。

  • 表示函数结果的变量总是从undefined每次调用一个函数。
  • 如果你希望调用范围中的指针指向带有指针结果的函数结果,那么你必须使用指针赋值。
  • >
  • 如果分配了一个指针,您需要有一个匹配的解除分配。


错误,因为 getX setX first_entry 变量c>过程与特定于对象的状态在 getX 过程中的 setX 过程和过程实例特定状态中相混淆。

第一次 setX 曾被称为 x 特定的这个对象的指针组件会由于if语句而被取消(这里有一个糟糕的样式问题 - 小心if语句后有多个语句 - 它是只有第一个受条件限制!)。如果 setX 然后用不同 这个再次调用,则first_entry将被设置为false并且这个对象不能正确设置。相反,我怀疑你应该测试这个%TFX 同样,第一次 getX 被调用,否则未定义的函数结果变量 res 将被取消。但是,在随后的所有调用中,函数结果都不会被取消(函数结果开始时未定义函数的每次执行),然后将在关联的测试中错误地使用,也可能在取消分配语句中错误地使用。 (对于未定义的关联状态的指针调用关联(或取消分配)是非法的 - 注意到未定义的关联状态与关联状态不同。)



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是非常荒谬的。


This may be a specific question, but I think it pertains to how memory is handled with these two compilers (Compaq visual Fortran Optimizing Compiler Version 6.5 and minGW). I am trying to get an idea of best practices with using pointers in Fortran 90 (which I must use). Here is an example code, which should work "out of the box" with one warning from a gfortran compiler: "POINTER valued function appears on RHS of assignment", and no warnings from the other compiler.

   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

This program runs in both compilers. However, changing the loop from 10**4 to 10**5 causes a serious memory problem with gfortran.

Using CTR-ALT-DLT, and opening "performance", the physical memory increases rapidly when running in gfortran, and doesn't seem to move for the compaq compiler. I usually cancel before my computer crashes, so I'm not sure of the behavior after it reaches the maximum.

This doesn't seem to be the appropriate way to use pointers (which I need in derived data types). So my question is: how can I safely use pointers while maintaining the same sort of interface and functionality?

p.s. I know that the main program does not seem to do anything constructive, but the point is that I don't think that the loop should be limited by the memory, but rather it should be a function of run-time.

Any help is greatly appreciated.

解决方案

This code has a few problems, perhaps caused by misunderstandings around the language. These problems have nothing to do with the specific compiler - the code itself is broken.

Conceptually, note that:

  • There is one and only one instance of a saved variable in a procedure per program in Fortran 90.
  • The variable representing the function result always starts off undefined each time a function is called.
  • If you want a pointer in a calling scope to point at the result of a function with a pointer result, then you must use pointer assignment.
  • If a pointer is allocated, you need to have a matching deallocate.

There is a latent logic error, in that the saved first_entry variables in the getX and setX procedures are conflated with object specific state in the setX procedure and procedure instance specific state in the getX procedure.

The first time setX is ever called the x pointer component of the particular this object will be nullified due to the if statement (there's an issue of poor style there too - be careful having multiple statements after an if statement - it is only the first one that is subject to the conditional!). If setX is then called again with a different this, first_entry will have been set to false and the this object will not be correctly set-up. I suspect you are supposed to be testing this%TFX instead.

Similarly, the first time getX is called the otherwise undefined function result variable res will be nullified. However, in all subsequent calls the function result will not be nullified (the function result starts off undefined each execution of the function) and will then be erroneously used in an associated test and also perhaps erroneously in a deallocate statement. (It is illegal to call associated (or deallocate for that matter) on a pointer with an undefined association status - noting that an undefined association status is not the same thing as dissociated.)

getX returns a pointer result - one that is created by the pointer being allocated. This pointer is then lost because "normal" assignment is used to access the value that results from evaluating the function. Because this pointer is lost there can't be (and so there isn't...) a matching deallocate statement to reverse the pointer allocation. The program therefore leaks memory. What almost certainly should be happening is that the thing that captures the value of the getX function in the main program (f in this case, but f is used for multiple things, so I'll call it f_ptr...) itself should be a pointer, and it should be pointer assigned - f_ptr => getX(f1). After the value of f_ptr has been used in the subsequent setX call and write statement, it can then be explicitly deallocated.

The potential for accidental use of normal assignment when pointer assignment is intended is one of the reasons that use of functions with pointer results is discouraged. If you need to return a pointer - then use a subroutine.

Fortran 95 simplifies management of pointer components by allowing default initialization of those components to NULL. (Note that you are using default initialization in your type definition - so your code isn't Fortran 90 anyway!)

Fortran 2003 (or Fortran 95 + the allocatable TR - which is a language level supported by most maintained compilers) introduces allocatable function results - which remove many of the potential errors that can otherwise be made using pointer functions.

Fortran 95 + allocatable TR support is so ubiquitous these days and the language improvements and fixes made to that point are so useful that (unless you are operating on some sort of obscure platform) limiting the language level to Fortran 90 is frankly ridiculous.

这篇关于康柏视觉fortran和gfortran之间的Fortran 90差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆