在select case结构中声明参数

时间:2016-08-08 02:52:45

标签: fortran

我写了一个简单的演示代码,以快速的方式呈现我的问题。这是代码,无法成功构建。

main.f90时

PROGRAM test
IMPLICIT NONE

    INTEGER    ::   a
    a = 1
    CALL sub(a)

END PROGRAM

sub.f90

SUBROUTINE sub(a)
IMPLICIT NONE

    INTEGER    ::   a
    SELECT CASE(a)
        CASE(1)
            INTEGER     ::   b,c
            b = a
            c = a*2
        CASE(2)
            INTEGER     ::   b(4),c(4)
            b(:) = a
            c(:) = a*2
    END SELECT

END SUBROUTINE

我尝试编译,但错误显示子例程文件中出现“意外的数据声明语句”。这是否意味着我无法在SELECT CASE结构中声明参数类型?问题是我想在主程序中定义a的值并将其传递给子程序sub(a)。 b和c的参数类型应由a决定,因此我无法事先确定。我还想将b和c的值传递回主程序,我不知道该怎么做。那我该怎么做呢?谢谢。

3 个答案:

答案 0 :(得分:3)

因此,您实际上是在询问如何从某个子例程返回标量或数组,而不是如何声明构造局部变量。在这种情况下,请考虑使用两个单独的子例程。一个版本用于标量,一个用于数组。如果需要,可以在一个名称下将它们作为通用过程重载。

还要考虑ELEMENTAL,但如果使用标量a,它将不适用于数组。

如果您仍想知道如何声明局部变量:

变量只能在过程的开头或块的开头声明。这是最新版本的最常见编译器支持的Fortran 2008功能(来自至少GNU和Intel的PC编译器)。

SELECT CASE(a)
    CASE(1)
        BLOCK
          INTEGER     ::   b,c
          b = a
          c = a*2
        END BLOCK

答案 1 :(得分:2)

您发现的代码是非法的,正如您所发现的那样。现在有些人已经指出了BLOCK陈述的2008特征,如果这是你需要的,你可以试试。但是我想了解更多关于你想要做什么的事情。

你给他们同名的这个事实告诉我你以后想以同样的方式对待他们,这让事情变得非常棘手。

以下是一些替代方案:

1)使用单独的变量:

INTEGER :: b_scalar, c_scalar, b_array(4), c_array(4)
select case(a)
    case(1)
        b_scalar = a
        c_scalar = 2*b_scalar
    case(2)
        b_array = a
        c_array = 2*b_array
end select

2)使用可分配的数组:

integer, dimension(:), allocatable :: b, c
select case(a)
    case(1)
        allocate(b(1), c(1))
    case(2)
        allocate(b(4), c(4))
end select
b = a
c = 2 * b

现在你必须记住bc是数组,可能是长度为1.你必须这样对待它们。

所有这些都有优点和缺点。不知道你为什么要做你正在做的事情,我真的不知道如何最好地为你提供建议。

关于你的第二个问题:返回它们的简单方法是INTENT(OUT)伪参数。这是一个有效的例子:

module mod_allocatable
contains
    subroutine my_sub(a, b, c)
        implicit none
        integer, intent(in) :: a
        integer, dimension(:), allocatable, intent(out) :: b, c
        if (allocated(b)) deallocate(b)
        if (allocated(c)) deallocate(c)
        select case(a)
            case(1)
                allocate(b(1), c(1))
            case(2)
                allocate(b(4), c(4))
        end select
        b = a
        c = 2 * b
      end subroutine my_sub
end module mod_allocatable

program test_alloc
    use mod_allocatable
    implicit none
    integer :: a
    integer, allocatable, dimension(:) :: b, c
    a = 1
    call my_sub(a, b, c)
    print *, "b is ", b
    print *, "c is ", c
end program test_alloc

答案 2 :(得分:0)

这不是太优雅......

  SUBROUTINE sub(a)
    IMPLICIT NONE

    INTEGER,               INTENT(IN)   ::   a
    INTEGER, DIMENSION(:), ALLOCATABLE  :: b, c

    SELECT CASE(a)
        CASE(1)
            IF(ALLOCATED(B)) THEN
              IF(UBOUND(B)) .NE. 1) THEN
                DEALLOCATE(B)
                ALLOCATE(B(1))
              ENDIF
            ELSE
              ALLOCATE(B(1))
            ENDIF

            IF(ALLOCATED(C)) THEN
              IF(UBOUND(C)) .NE. 1) THEN
                DEALLOCATE(c)
                ALLOCATE(C(1))
              ENDIF
            ELSE
              ALLOCATE(C(1))
            ENDIF

            b = a
            c = a*2
        CASE(2)
            IF(ALLOCATED(B)) THEN
              IF(UBOUND(B)) .NE. 4) THEN
                DEALLOCATE(B)
                ALLOCATE(B(4))
              ENDIF
            ELSE
              ALLOCATE(B(4))
            ENDIF

            IF(ALLOCATED(C)) THEN
              IF(UBOUND(C)) .NE. 4) THEN
                DEALLOCATE(C)
                ALLOCATE(C(4))
              ENDIF
            ELSE
              ALLOCATE(C(4))
            ENDIF

            b(:) = a
            c(:) = a*2
        CASE(DEFAULT)
            WRITE(*,*)'how did we get here?... a=',a
    END SELECT

END SUBROUTINE Sub