【问题标题】:Passing a user defined data type allocatable array传递用户定义的数据类型可分配数组
【发布时间】:2017-07-20 15:40:30
【问题描述】:

我可以使用可分配数组作为其数据类型来定义用户定义的数据类型。

当我们仍在同一个子例程中时,分配工作完美。 但我不知道如何将这种用户定义的数据类型作为子程序参数传递。

英特尔编译器显示错误# 6530

"Error  1    error #6530: The array spec for this component must be of explicit shape and each bound must be an initialization expression."

代码已在下面共享以显示错误。它是用 FORTRAN 77 编写的。我正在使用 FORTRAN 77,因为我必须将此代码附加到仅接受 FORTRAN 77 文件的 Abaqus 用户子例程中。


  PROGRAM DERIVED_DATA_TYPE_CHECK

  IMPLICIT NONE

  INTEGER :: I,J,A,B
  TYPE SS
      SEQUENCE
      DOUBLE PRECISION, DIMENSION(:,:), ALLOCATABLE :: S1
  END TYPE SS

  TYPE (SS),DIMENSION(:,:),ALLOCATABLE :: SS_

  A=10
  B=10

  ALLOCATE (SS_(A,B))
  ! ALLOCATING THE VARIABLE S1 DIMENSIONS
  ! EVERY ALLOCATABLE VARIABLE HAS THE SAME SIZE AS
  ! THE TOTAL NUMBER OF STRUCTURE (TYPE)
  DO I = 1,A
      DO J = 1,B
          ALLOCATE(SS_(I,J)%S1(A,B))
      ENDDO
  ENDDO

  CALL PASS_ARG(SS_,A,B)

  END


  SUBROUTINE PASS_ARG(SS_,A,B)

  IMPLICIT NONE

  INTEGER :: A,B

  TYPE SS
      SEQUENCE
      DOUBLE PRECISION, DIMENSION(A,B) :: S1
  END TYPE SS

  TYPE (SS), DIMENSION (A,B) :: SS_

  END

编译时程序报错如下图:

----------
Error   2    error #6530: The array spec for this component must be of explicit shape and each bound must be an initialization expression.   [S1]   
----------

一定有办法解决这个问题。我想远离常见的块或模块。无论如何我不能在 Fortran 中使用模块。

为了避免这个错误,我在主程序和调用子程序中都使用了可分配变量。然后编译程序,但在执行时,它显示错误“分配已完成多次”。

最后我想我将不得不使用一些全局常量.....我猜。

【问题讨论】:

  • 您的代码不是 FORTRAN 77。甚至没有接近。它与 FORTRAN 77 绝对不兼容。在 FORTRAN 77 中没有像 allocatable::type 这样的东西。
  • 好的........
  • ok........所以你能用你的更正编译程序吗......并发表你的建议...... .......我不在乎......直到这个特殊的小程序在f90或f77中运行............
  • 我想远离常见的块或模块但是在这种情况下,模块正是你应该想要的。顺便说一句,子程序中声明的类型ss不是程序中声明的类型ss

标签: fortran subroutine allocatable-array


【解决方案1】:

可以在没有模块的情况下做你想做的事,但这并不意味着你应该。但首先,让我们看看编译器抱怨的问题。

考虑派生类型定义

type t
  real x(i)
end type

该类型有一个数组组件x(绑定i);它是一个显式形状数组。在这种情况下,绑定的i 必须是规范表达式。在这里,这实质上意味着i 必须是一个常量。

在问题的子程序pass_arg 中,组件的边界不是常量,而是虚拟参数。这就是编译器抱怨的原因。

要解决这个问题,您应该再次使子程序类型中的组件可分配。然后,您甚至不需要传递 ab:边界将从数组的分配状态中获得。


现在,您说您想在不使用模块的情况下执行此操作。通过上面的更正,您可以做到这一点。但是,我强烈建议您不要这样做:这仅是因为派生类型是序列类型。使用序列类型有限制且容易出错:

  • 序列类型的组件可能是有限的,并且不能有类型绑定的过程;
  • 您必须准确地在每个使用它的地方重复该类型的定义;
  • 类型中不能有私有组件。

最好创建一个模块并定义一次派生类型(并使其成为非序列类型)。


问题示例的第二个选项是使用参数化派生类型:

type ss(a,b)
  type, len :: a, b
  ! Not a sequence type, define once in a module
  double precision, dimension(a,b) :: s1
end type

在主程序中可以这样使用(为了清楚起见,使用命名常量)

use mod_with_type_ss
implicit none
integer, parameter :: a=10, b=10
type(ss(a,b)) ss_(a,b)
call pass_arg(ss)
end

子程序可以是这样的

subroutine pass_arg(ss_)
  use mod_with_type_ss
  type(ss(*,*)), intent(in) :: ss_  ! The type parameters are assumed
  ...
end subroutine

【讨论】:

    猜你喜欢
    • 2021-05-31
    • 2016-05-08
    • 2016-07-16
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-24
    相关资源
    最近更新 更多