0

我想在 Mac OS X 10.8.2 中使用 PGI Fortran 编译器版本 12.10-0 在 Fortran 中实现一个通用的双链表来保存代码。这是我的原型,包括 3 个文件:

---> 文件 1:

! ----------------------------------------------------------------------------
! Description: 
! 
!   This module provides several basic data structures, e.g. double linked list. 
! 
! Authors: 
! 
!   Li Dong <dongli@lasg.iap.ac.cn> - 2012-11-11 
! ----------------------------------------------------------------------------

module basic_data_structure 

    implicit none 

    private 

    public list_elem_t, list_t 

    type list_elem_t 
        class(list_elem_t), pointer :: prev, next 
    end type list_elem_t 

    type list_t 
        integer :: num_elem = 0 
        class(list_elem_t), pointer :: head, tail 
    contains 
        procedure :: append => list_append 
        procedure :: insert => list_insert 
        procedure :: final => list_final 
    end type list_t 

contains 

    ! ------------------------------------------------------------------------
    ! Description: 
    ! 
    !   The following list_* are the type-bound procedures of double linked 
    !   list data structure. 
    ! 
    ! Authors: 
    ! 
    !   Li Dong - <dongli@lasg.iap.ac.cn> - 2012-11-11 
    ! ------------------------------------------------------------------------

    subroutine list_append(this, elem) 

        class(list_t), intent(inout) :: this 
        class(list_elem_t), intent(out), pointer :: elem 

        character(50), parameter :: sub_name = "list_append" 

        allocate(elem)
        if (this%num_elem == 0) then
            this%head => elem
            nullify(this%head%prev)
            this%tail => this%head
        else
            this%tail%next => elem
            elem%prev => this%tail
            this%tail => elem
        end if
        nullify(this%tail%next) 
        this%num_elem = this%num_elem+1 

    end subroutine list_append 

    subroutine list_insert(this, existed_elem, elem) 

        class(list_t), intent(inout) :: this 
        class(list_elem_t), intent(inout), pointer :: existed_elem 
        class(list_elem_t), intent(out), pointer :: elem 

        character(50), parameter :: sub_name = "list_insert" 

        ! TODO: Check existed_elem is allocated. 
        ! TODO: Check existed_elem is one element of this. 

        allocate(elem) 
        elem%prev => existed_elem 
        elem%next => existed_elem%next 
        if (associated(existed_elem%next)) then 
            existed_elem%next%prev => elem 
            existed_elem%next => elem 
        end if 
        this%num_elem = this%num_elem+1 

    end subroutine list_insert 

    subroutine list_final(this) 

        class(list_t), intent(inout) :: this 

        class(list_elem_t), pointer :: elem 
        integer i 

        elem => this%head 
        do i = 1, this%num_elem-1 
            elem => elem%next 
            if (associated(elem%prev)) deallocate(elem%prev) 
        end do 
        deallocate(this%tail) 

    end subroutine list_final 

end module basic_data_structure

---> 文件 2

! ----------------------------------------------------------------------------
! Description: 
! 
!   This module manages the model variables. 
! 
! Authors: 
! 
!   Li Dong <dongli@lasg.iap.ac.cn> - 2012-11-11 
! ----------------------------------------------------------------------------

module variable 

    use basic_data_structure 

    implicit none 

    private 

    public variable_register 
    public variable_final 

    public var_t, var_1d_t 

    integer, parameter :: A_GRID = 1 
    integer, parameter :: B_GRID = 2 
    integer, parameter :: C_GRID = 3 

    type, extends(list_elem_t) :: var_t 
        character(10) name 
        character(50) long_name 
        character(20) units 
        integer grid_type 
    end type var_t 

    type, extends(var_t) :: var_1d_t 
        real(8), allocatable :: array(:) 
    end type var_1d_t 

    type, extends(var_t) :: var_2d_t 
        real(8), allocatable :: array(:,:) 
    end type var_2d_t 

    type(list_t) var_list 

contains 

    ! ------------------------------------------------------------------------
    ! Description: 
    ! 
    !   Register a variable. 
    ! 
    ! Authors: 
    ! 
    !   Li Dong <dongli@lasg.iap.ac.cn> - 2012-11-11 
    ! ------------------------------------------------------------------------

    subroutine variable_register(name, var) 

        character(*), intent(in) :: name 
        class(var_t), intent(inout), pointer :: var 

        character(50), parameter :: sub_name = "variable_register" 

        select type (var) 
        type is (var_1d_t) 
            print *, "---> Register a 1D variable """//trim(name)//"""." 
        type is (var_2d_t) 
            print *, "---> Register a 2D variable """//trim(name)//"""." 
        type is (var_t) 
            print *, "---> Oh, no!" 
        class default 
            print *, "---> Unknown variable type """//trim(name)//"""." 
        end select 

        call var_list%append(var) 

        ! -------------------------------> PROBLEM IS HERE 
        select type (var) 
        type is (var_1d_t) 
            print *, "---> Register a 1D variable """//trim(name)//"""." 
        type is (var_2d_t) 
            print *, "---> Register a 2D variable """//trim(name)//"""." 
        type is (var_t) 
            print *, "---> Oh, no!" 
        class default 
            print *, "---> Unknown variable type """//trim(name)//"""." 
        end select 

    end subroutine variable_register 

    ! ------------------------------------------------------------------------
    ! Description: 
    ! 
    !   Clean the registered variables. 
    ! 
    ! Authors: 
    ! 
    !   Li Dong <dongli@lasg.iap.ac.cn> - 2012-11-11 
    ! ------------------------------------------------------------------------

    subroutine variable_final() 

        character(50), parameter :: sub_name = "variable_final" 

        call var_list%final() 

    end subroutine variable_final 

end module variable

---> 文件 3:

program test_variable 

    use variable 

    implicit none 

    type(var_1d_t), pointer :: a 

    call variable_register("a", a) 
    call variable_final() 

end program test_variable

运行结果是:

MacBook-Pro:sandbox dongli$ ./test_variable 
 ---> Register a 1D variable "a". 
 ---> Unknown variable type "a". 

为什么添加列表后,类型var变为未知类型,如何实现预期功能?

4

1 回答 1

1

F2008 12.5.2.5 p2 在指针和可分配的虚拟参数方面说:“当且仅当关联的虚拟参数是多态的时,实际参数应该是多态的......”。

variable_register 中的虚拟参数var是一个多态指针。a主程序中的实际参数不是。你的程序出错了,Fortran 处理器不需要诊断这个错误(尽管在这种特殊情况下它应该很容易检测到这个错误)。

F2008 12.5.2.5 中的同一段接着说“......实际参数的声明类型应与虚拟参数的声明类型相同”。list_append 中的虚拟参数是声明类型的多态指针list_elem_t。实际参数是声明类型的多态指针var_t。它们不一样——你的程序错误更多。同样,Fortran 处理器不需要对此进行诊断,但在这种情况下它应该很容易做到这一点。

因为您的程序出错,所以任何事情都可能发生,但在相关说明中 - elemlist_append 的参数已声明INTENT(OUT)。这意味着在该过程开始时, elem 的指针关联状态是未定义的——您不知道它指向什么(或其动态类型)。list_append 中的 allocate 语句然后分配声明类型的对象elem,即list_elem_t(作为最终参数的指针和作为“中间”参数的指针现在已经指向它们各自声明类型的父级的事实是存在上述 12.5.2.5 中引用的限制的原因 - 请阅读 F2008 中的注释 12.27)。您的选择类型不会检查该选项。

于 2012-11-15T02:10:41.567 回答