指向派生类型中的子例程的 Fortran 过程指针

2023-11-26

在 Fortran 中,我需要派生类型中的过程指针,该指针可以指向多个子例程之一。这个问题在 SO 上似乎很常见:

Fortran 将过程保存为派生类型中的属性

Fortran 2003 中的类型绑定过程重载

没有与此类型绑定通用子例程调用相匹配的特定子例程

带有过程参数的通用类型绑定过程

类型绑定过程作为参数

仅举几例。这个问题的答案为功能在第一个参考文献中提供得非常好。

但是,我仍然不清楚在类型绑定过程指针指向子例程的情况下如何很好地开发此类代码的方法。困难似乎在于没有与返回的内容相关联的类型(因为没有任何内容真正“返回”)。

我还想指出一个细微差别,虽然在更新的 fortran 标准(2003,2008)中可能存在一个简单的解决方案,但该解决方案可能不适用于所有编译器,这在将来可能会出现问题。所以我对编译器友好的解决方案感兴趣。

我有一个当前可以工作的小代码(如下所示),但在我的大代码中,我在派生类型中使用过程指针的文件中遇到内部编译器错误(也如下所示)。我的问题是:我可以对下面的代码做什么

1)严格使用显式接口

2)最大化传递给编译器的信息

3) 确保代码在尽可能多的编译器之间可移植(即使用 fortran 90 / 95 标准)。

上述条件能满足到什么程度(1最重要)?是否有可能满足上述所有这些标准?我知道“满足所有这些标准”是主观的,但我认为对于关于函数而不是子例程的同一问题,答案是“是”。

 gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)

小代码:

  module subs_mod
  implicit none
  public :: add,mult
  contains
  subroutine add(x,y,z)
    implicit none
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y+z
  end subroutine
  subroutine mult(x,y,z)
    implicit none
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y*z
  end subroutine
  end module

  module type_A_mod
  use subs_mod
  implicit none
  public :: type_A,init,operate
  type type_A
    procedure(),pointer,nopass :: op
  end type
  contains
  subroutine init(A,op)
    implicit none
    external :: op
    type(type_A),intent(inout) :: A
    A%op => op
  end subroutine
  subroutine operate(A,x,y,z)
    implicit none
    type(type_A),intent(in) :: A
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    call A%op(x,y,z)
  end subroutine
  end module

  program test
  use type_A_mod
  use subs_mod
  implicit none
  type(type_A) :: A
  integer :: x
  call init(A,mult)
  call operate(A,x,3,5)
  write(*,*) 'x = ',x
  end program

大代码中的编译器错误:

    f951.exe: internal compiler error: Segmentation fault
    libbacktrace could not find executable to open
    Please submit a full bug report,
    with preprocessed source if appropriate.
    See <http://sourceforge.net/projects/mingw-w64> for instructions.

UPDATE

这是一个小修改,可以为编译器提供更多信息,但我还没有在大代码上尝试过这个。然而,这似乎是武断的,我不知道这是否有帮助。

  ...
  function add(x,y,z) result(TF)
  ...
    logical :: TF
    x = y+z
    TF = .true.
  end function
  function mult(x,y,z) result(TF)
  ...
    logical :: TF
    x = y*z
    TF = .true.
  end function
  end module

  module type_A_mod
  ...
  type type_A
    procedure(logical),pointer,nopass :: op
  end type
  ...
  subroutine init(A,op)
    implicit none
    logical,external :: op
  ...
  end subroutine
  subroutine operate(A,x,y,z)
  ...
    logical :: TF
    TF = A%op(x,y,z)
  end subroutine
  end module

  program test
  ...
  end program

解决方案评论只是对解决方案(由 @IanH 提供)进行评论:还有一个额外的问题,那就是我有一些派生类型进入抽象接口,根据Fortran 2003的新特性, the Import应包含语句以使抽象接口知道任何进入的派生类型。这是一个小的工作示例,将其应用于大代码,可以减轻我遇到的内部编译器错误:)

  module DT_mod
  implicit none
  private
  public :: DT
  type DT
    integer :: i
  end type
  contains
  end module

  module subs_mod
  use DT_mod
  implicit none
  private
  public :: add,mult,op_int

  abstract interface
  subroutine op_int(d,x,y,z)
    import :: DT
    implicit none
    type(DT),intent(inout) :: d
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
  end subroutine
  end interface

  contains
  subroutine add(d,x,y,z)
    implicit none
    type(DT),intent(inout) :: d
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y+z
    d%i = 1
  end subroutine
  subroutine mult(d,x,y,z)
    implicit none
    type(DT),intent(inout) :: d
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y*z
    d%i = 2
  end subroutine
  end module

  module type_A_mod
  use DT_mod
  use subs_mod
  implicit none
  private
  public :: type_A,init,operate
  type type_A
    procedure(op_int),pointer,nopass :: op
  end type
  contains
  subroutine init(A,op)
    implicit none
    procedure(op_int) :: op
    type(type_A),intent(inout) :: A
    A%op => op
  end subroutine
  subroutine operate(A,d,x,y,z)
    implicit none
    type(DT),intent(inout) :: d
    type(type_A),intent(in) :: A
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    call A%op(d,x,y,z)
  end subroutine
  end module

  program test
  use type_A_mod
  use subs_mod
  use DT_mod
  implicit none
  type(type_A) :: A
  type(DT) :: d
  integer :: x,y,z
  y = 3; z = 5
  call init(A,mult)
  call operate(A,d,x,y,z)
  write(*,*) 'x,y,x = ',y,z,x
  write(*,*) 'd%i = ',d%i
  end program

任何帮助是极大的赞赏。


直到 Fortran 2003 之前,过程指针才成为标准语言的一部分,因此如果您想使用它们,那么 Fortran 95 兼容性就无关紧要了。

内部编译器错误是编译器的错误,无论提供给编译器的源是什么。

不存在类型绑定过程指针这样的东西。您要么有一个类型绑定过程 - 这是在派生类型构造中的 CONTAINS 之后声明的东西,要么有一个过程指针 - 它可以是类型的组件或独立对象。作为组件的过程指针是派生类型对象值的一部分 - 它可以在运行时与不同的过程相关联。类型绑定过程是类型声明的固定属性。

如果您希望过程指针(或虚拟过程)具有显式接口,则必须在过程声明语句的括号内提供接口名称。

procedure(interface_name_goes_here) [, pointer, ...] :: thing_being_declared

提供的接口名称可以是可访问的特定过程的名称(包括先前由不同的过程声明语句声明的名称),也可以是抽象接口的名称。

(如果过程声明语句中的接口名称是一个类型,就像示例代码中的组件一样,则声明的过程是一个具有给定类型结果的函数,具有隐式接口。

如果过程声明语句中的接口名称完全缺失,则声明的过程可能是具有隐式接口的函数或子例程(其后续使用必须与其中之一保持一致)。)

因此,假设您想声明一个具有与函数显式接口(与问题标题相反)的过程指针组件,其特征与add or mult在你的第二段代码中:

TYPE type_A
  PROCEDURE(the_interface), POINTER, NOPASS :: op
END TYPE type_A

ABSTRACT INTERFACE
  FUNCTION the_interface(x, y, z) RESULT(tf)
    IMPLICIT NONE
    ! function modifying arguments - poor style!!!
    INTEGER, INTENT(INOUT) :: x
    INTEGER, INTENT(IN) :: y, z
    LOGICAL :: tf
  END FUNCTION the_interface
END INTERFACE

如果您希望过程指针成为具有显式接口的子例程(这比修改其参数的函数更好) - 适当地更改抽象接口。

中的虚拟程序init子例程不必是指针 - 内部init你没有改变什么op事物引用 - 你只是指向它的另一个指针:

PROCEDURE(the_interface) :: op

当您的虚拟过程和过程指针使用显式接口声明时,我希望合理的编译器能够诊断特征中的任何不匹配情况。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

指向派生类型中的子例程的 Fortran 过程指针 的相关文章

  • ctags 和 Fortran 的接口

    我想知道如何让 ctags 使用 Fortran 中的接口 例如 INTERFACE SOME ROUTINE MODULE SOME ROUTINE A MODULE SOME ROUTINE B END SOME ROUTINE 因此
  • ipython 和 ipython 笔记本之间奇怪的准确度差异,然后使用 fortran 模块和 f2py

    当使用用 f2py 编译的 fortran 模块时 我遇到了 ipython 和 ipython 笔记本之间奇怪的准确性差异 我的 Fortran 模块是 subroutine tt string fmt n num out implici
  • 将标量和数组(任意维度)从 Fortran 传递到 C

    我有以下名为的 Fortran 子例程show value调用一个名为的 C 函数show value INTERFACE SUBROUTINE show value variable BIND C name show value USE
  • Intel Fortran 错误 #6633:实际参数的类型与虚拟参数的类型不同

    对于可能在这里提出这样一个基本问题 我深表歉意 我是使用英特尔 Fortran 编程的新手 所以我认为在这种情况下 我不知道有一些东西丢失或组织错误 如果有人能在这方面帮助我 我将不胜感激 问题是我在编译代码时看到以下错误 而我相信我已经声
  • 函数声明“sub function($$)”是什么意思?

    我使用 Perl 一段时间了 但今天我遇到了这段代码 sub function1 snip 这在 Perl 中意味着什么 它是一个带有原型 http perldoc perl org perlsub html Prototypes这需要两个
  • 使用 MPI 派生数据类型

    我正在学习 Fortran 中的 BCASTing 数据类型 并且有一个代码可以从终端获取两个值并将它们显示在每个进程上 对于整数 整数和整数 实数类型的组合 value1 value2 这是有效的 但是对于整数 实数 8 的组合 它会失败
  • 使用 Iso_Fortran_Env 设置函数的 Kind 值

    如何使用 ISO Fortran Env 的内在函数以 Fortran 2008 惯用的方式设置函数的返回 KIND 值 通常在主程序中 我可以使用 ISO Fortran 内在函数 如下所示 program name here use i
  • LAPACK 反演例程奇怪地混合了所有变量

    我正在使用 Fortran 进行编程 并尝试使用 Lapack 包中的 DGETRI 矩阵逆变器 http www netlib org lapack explore html df da4 dgetri 8f html http www
  • Fortran 读取混合字符串和数字数据

    我在读取语句时遇到问题 我更喜欢 Fortran90 尽管如果有帮助的话其他版本也是可能的 我的文件中有一堆数据行 可以描述为 以空格分隔 没有固定的格式 包含一个字符串 后跟 7 个数字 字符串包含正斜杠 这是一个例子 maxele OS
  • 在 Fortran 中读取行数已知但每行条目数未知的数据文件

    如何读取包含已知行数但每行中的条目数未知的数据文件 例如如果我的数据文件包含类似的内容 1 3 4 5 6 7 8 9 1 3 5 6 4 5 6 7 8 3 5 6 7 8 4 5 7 8 即三行 但每行中的数据未知 有一次我需要来自一行
  • Perl 调用带括号和不带括号的方法

    一些 Perl 书籍建议在调用类方法时使用括号 称这有助于使解析器不必猜测代码的意图 然而 我见过的几乎所有 Perl 代码 包括 cpan 上的模块 在调用不带参数的方法时很少使用括号 省略这些括号是正常的还是我应该总是输入它们 我编写了
  • Fortran 读取混合文本和数字

    我正在使用 Fortran 90 读取包含以下格式数据的文件 number 125 var1 2 var2 1 var3 4 number 234 var1 3 var2 5 var3 1 我尝试了以下命令并且工作正常 read 2 tem
  • 使用命令行查找数据文件的行数

    有一种常规方法 逐行读取并检查iostat每次读数时都会达到非零或负值 不过 我想打电话system command 例行公事和 使用wc l命令来计算数量 然后想要分配要放置数据的数组的维度 例如 我以两种方式打印行数 Program T
  • 如何用好Fortran语句标签?

    我正在开发一个用 Fortran 95 编写的模型 我对此完全陌生 语句标签的概念似乎很奇怪 到目前为止我只找到了标签可以由作者任意决定的解释 通常以 10 为增量 除了更容易地找出语句的结尾位置之外 这些标签还有其他实际用途吗 以及关于如
  • Fortran PURE 函数可以使用全局参数吗?

    在我看来 Fortran 中所谓的纯函数对于那些使用函数式编程的人来说似乎不够纯粹 这是我的问题 假设我有以下代码 MODULE basics IMPLICIT NONE INTEGER PARAMETER dp kind 1 0d0 RE
  • gfortran 未定义的引用

    我正在尝试编译一个依赖很多东西的程序 我使用并修改了提供的 makefile 来代表我的计算机设置 但在编译的最后一步中我不断收到许多未定义的引用 导致问题的命令行是 gfortran o cosmomc ParamNames o Matr
  • 如何在 Fortran 90 中迭代包含数字、单词和空格的字符串?

    文件说明 STL文件由以下部分组成 solid
  • 如何在 conda 中静音或抑制 gfortran (或 clang?)后端?

    我一直致力于构建一个非常特殊的 conda 环境 专为python and R与串扰使用rpy2 我想出的方法可以安装正确的R包如下 install main environment sh now date T echo Start Tim
  • 将数组从 .npy 文件读入 Fortran 90

    我使用 Python 以二维数组 例如 X 的形式生成一些初始数据 然后使用 Fortran 对它们进行一些计算 最初 当数组大小约为 10 000 x 10 000 时 np savetxt 在速度方面表现良好 但是一旦我开始增加数组的维
  • 如何在Fortran代码中将二维数组转换为一维数组?

    如何将 r i j 转换为一维数组以便可以轻松地对数字进行排序 program sort implicit none character CN 8 O 7 integer j iconf nconf integer i nbins t in

随机推荐