使用定义的输入过程从Fortran中的二进制文件读取错误值 [英] Reading bad values from binary file in Fortran with a defined input procedure

查看:174
本文介绍了使用定义的输入过程从Fortran中的二进制文件读取错误值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图编写一个简单的代码,该代码将具有相同父抽象类的某些对象带入一个二进制文件中,然后将它们读回。

I'm trying to write a simple code, which takes some objects with the same parental abstract class, stores them into a binary file and reads them back.

我的代码如下所示:

module m
    implicit none

    type :: container
        class(a), allocatable :: item
    end type container

    type, abstract :: a
        character(20), public :: obj_type
        integer, public :: num
    contains
        procedure :: write_impl => write_a
        procedure :: read_impl => read_a

        generic            :: write(unformatted) => write_impl
        generic            :: read(unformatted)  => read_impl
    end type a

    type, extends(a) :: b
        integer, public :: num2
    contains
        procedure :: write_impl => write_b
        procedure :: read_impl => read_b
   end type b

    type, extends(a) :: c
    end type c

contains

    subroutine write_a(this, unit, iostat, iomsg)
        class(a), intent(in)    :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        write(unit, iostat=iostat, iomsg=iomsg) this%num
    end subroutine write_a

    subroutine read_a(this, unit, iostat, iomsg)
        class(a), intent(inout) :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        read(unit, iostat=iostat, iomsg=iomsg) this%num
    end subroutine read_a

    subroutine write_b(this, unit, iostat, iomsg)
        class(b), intent(in)    :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        write(unit, iostat=iostat, iomsg=iomsg) this%num, this%num2
    end subroutine write_b

    subroutine read_b(this, unit, iostat, iomsg)
        class(b), intent(inout) :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        read(unit, iostat=iostat, iomsg=iomsg) this%num, this%num2
    end subroutine read_b
end module m

program mwe
    use m

    implicit none

    class(a), allocatable :: o1, o2, o3, o4
    class(container), allocatable :: arr(:)
    integer :: i, arr_size, tmp
    character(20) :: str_tmp

    o1 = b('b', 1, 2)
    o2 = c('c', 3)

    allocate(arr(2))
    arr(1)%item = o1
    arr(2)%item = o2

    select type(t => o1)
        type is(b)
        write(*,*) t%num, t%num2
    end select

    select type(t => arr(1)%item)
        type is(b)
        write(*,*) t%num, t%num2
    end select

    write(*,*) 'Write into binary'
    ! WRITE size
    open(123, file='test5.dat', form='unformatted')
    write(123) SIZE(arr)

    do i=1,2 
        write(123) arr(i)%item%obj_type
            if(arr(i)%item%obj_type .eq. 'b') then
                select type(t => arr(i)%item)
                    type is(b)
                    write(123) t
                end select
            else if(arr(i)%item%obj_type .eq. 'c') then
                select type(t => arr(i)%item)
                    type is(c)
                    write(123) t
                end select
            end if
    end do
    close(123)

    write(*,*) 'Read from binary'
    open(123, file='test5.dat', form='unformatted')
    read(123) arr_size
    write(*,*) 'array size: ', arr_size

    do i=1,2
        read(123) str_tmp
        write(*,*) str_tmp
        if(allocated(o3)) deallocate(o3)
        if(str_tmp .eq. 'b') then
            allocate(b :: o3)
            select type(t => o3)
                type is(b)
                read(123) t
                write(*,*) t%num, t%num2  ! BAD OUTPUT
            end select
        else if(str_tmp .eq. 'c') then
            allocate(c :: o3)
            select type(t => o3)
                type is(c)
                read(123) t
                write(*,*) t%num
            end select
        end if

    end do

end program mwe

问题是读取 o1 -类型为 b ,即该对象具有两个组成部分- num num2 。我将其存储起来,自然希望读取的值与写入的值相同。

The problem is, with reading of o1 - it's of the type b, i.e. this object has two components - num and num2. I store it and I would naturally expect the read values to be the same, as the written ones.

但是我得到的异常行为与在Fortran数组中删除变量?。在这个问题中,这是由于初始化数组时分配语法错误而引起的,但是在这种情况下,我完全不知道为什么我的输出看起来像这样:

But I'm getting the same strange behavior as described in Variables being deleted in Fortran Arrays? . In that question it was caused by the bad assignment syntax while initializing an array, but in this case I'm completely clueless why my output looks like this:

           1           2
           1           2
 Write into binary
 Read from binary
 array size:            2
 b                   
           1           0
 c                   
           3

b 应该显然是1和2,而不是1和0。我在做什么错?

The values under b should be obviously 1 and 2, not 1 and 0. What am I doing wrong?

推荐答案

这里的问题是

select type(t => arr(i)%item)
type is(b)
  write(123) t
end select

实际上,实际上并不是选择过程 write_b 处理定义的输出。在处理定义的输入时,它也没有选择过程 read_b

ifort is not actually selecting the procedure write_b to process the defined output. It is also not selecting the procedure read_b when it comes to processing the defined input.

相反,过程 write_a read_a 被选中。

这是一个问题编译器,应报告给英特尔。一个相当乏味的解决方法是在那些过程中选择类型

This is a problem with the compiler and should be reported to Intel. A rather tedious workaround is to select type in those procedures.

这篇关于使用定义的输入过程从Fortran中的二进制文件读取错误值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆