3

我正在尝试破译一个 fortran 代码。它将指向函数的指针作为实际参数传递,而形式参数则是目标。它在主程序中定义并分配一个 globalDATA 类型的指针,然后调用一个传递该指针的函数:

module dataGLOBAL
 type globalDATA
   type (gl_1)      , pointer :: gl1
   type (gd_2)      , pointer :: gd2
   type (gdt_ok)    , pointer :: gdtok
   ...
   ...
 end type globalDATA
end module dataGLOBAL


Program main
....
....
use dataGLOBAL   
...
type(globalDATA),pointer :: GD

allocate(GD)
returnvalue = INIT(GD)
....
....
end

函数内容如下:

integer function INIT(GD) result(returnvalue)
....
....
use dataGLOBAL

type(globalDATA)  , target   :: GD

allocate (GD%gl1)
allocate (GD%gd2)
allocate (GD%gdtok)
....
....
end function INIT

这样做有什么意义?为什么主程序中的指针和目标结构的单个组件都必须分配?谢谢。

4

3 回答 3

9

一些事情可能会发挥作用......

  • 当您将指针作为实际参数提供给相应的虚拟参数不具有 POINTER 属性(此处为这种情况)的过程时,与虚拟参数关联的事物是实际参数指针的目标。所以在这种情况下,传递的东西是GD(在主程序中)指向的对象 - 由 allocate 语句分配的东西。(当实际参数和虚拟参数都具有 POINTER 参数时,则 POINTER 本身被“通过” - 您可以更改 POINTER 指向的内容,并且该更改会反映在调用范围中。)

  • 因为GD函数内部的哑元具有目标属性,所以函数内部的指针可以指向哑元。您没有显示此类指针的任何声明,但它们可能在省略的代码中。如果没有任何东西指向GD虚拟参数(包括在可能由 INIT 函数调用的任何过程中),那么 TARGET 属性是多余的,但除了抑制一些优化之外是无害的。

  • 具有指针属性的事物也(由语言规则自动)具有 TARGET 属性 - 因此GD在主程序中具有 TARGET 属性。GD在主程序和函数中都具有目标属性的事实可能是相关的,因为......

  • 当虚拟参数具有 TARGET 属性并且作为实际参数传递的事物具有 TARGET 属性时,与过程中的虚拟参数相关联的指针也是“通常”的(共索引事物/非连续存在异常/处理器依赖性数组/向量下标部分太复杂以至于我记不住)与相应的实际参数相关联。如果指针不是局部变量(可能是在模块中声明的指针),则此关联在过程结束后仍然存在。也许这与省略的代码有关。(或者,如果实际参数没有 TARGET 属性,则与虚拟参数关联的任何指针在过程结束时都将变为未定义。)

  • globalDATA类型的组件本身就是指针。因此,GD在主程序中是一个指向某物(由主程序中的单个 ALLOCATE 语句分配的东西)的指针,该指针本身包含指向其他东西的指针(那些其他东西由函数中的众多 ALLOCATE 语句分配)。您有两个级别的指针,因此有两个级别的 ALLOCATE。

  • 在 Fortran 2003(或带有“可分配 TR”的 Fortran 95)之前,您不能在派生类型中有 ALLOCATABLE 组件,也不能有 ALLOCATABLE 虚拟参数 - 当动态分配的需求与您必须使用的这些以前的限制相冲突时而是使用指针,即使您只是将指针用作值。我强烈怀疑您的代码可以追溯到这个时代(大约十年前,对可分配 TR 的支持变得普遍)。在非常“现代”的 Fortran 指针中(应该?)仅在您可能想要指向其他事物的变量时使用(其他事物包括“无”)。

于 2013-01-07T02:40:04.937 回答
2

对于本身包含指针的用户定义类型的指针变量,您必须同时分配(即创建存储)整个变量和组件指针。当整体变量为时,组件不会自动分配。有人做出了设计选择,在主程序中分配整体变量,在子程序中分配组件。也许他们认为分配整体变量很简单,但分配所有组件变得复杂,并希望将其归为子程序。

于 2013-01-07T02:23:36.333 回答
0

因为没有为虚拟参数指定指针属性,所以整个派生类型GD是从主代码(而不是指向它的指针)传递的。在子程序方面,你可以明确地写

integer function INIT(GD) result(returnvalue)
...
use dataGLOBAL

type(globalDATA), intent(inout), target :: GD

让它更清楚。虚拟参数的目标属性仅确保您可以通过指针分配指向子例程内的该参数。

只要您只操作派生类型的字段,而不是整个派生类型(例如通过分配或解除分配),无论您是INIT通过传递指针还是派生类型来调用例程,它都不会有区别本身。

正如在其他答案中已经指出的那样,该程序的目的似乎是将派生类型及其组件的分配彼此分开。这种策略的一个可能优点是可以将指针和静态分配的派生类型都传递给INIT例程。

于 2013-01-07T12:24:58.963 回答