Ошибка чтения из бинарного файла Fortran

Я пытаюсь написать короткий код, который сохраняет массив объектов с одним и тем же родительским классом в двоичный файл, а затем считывает их обратно. Я использую неформатированный двоичный вывод, так как считаю, что это самый простой способ сделать это.

Моя попытка здесь:

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(*,*) t%num, t%num2
                    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(*,*) t%num
                    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%num, t%num2  ! ERROR
                write(*,*) t%num, t%num2
            end select
        else if(str_tmp .eq. 'c') then
            allocate(c :: o3)
            select type(t => o3)
                type is(c)
                read(123) t%num
                write(*,*) t%num
            end select
        end if

    end do

end program mwe

Но код падает при попытке чтения из бинарного файла со следующей ошибкой:

forrtl: severe (67): input statement requires too much data, unit 123, file /home/martin/Desktop/test5.dat
Image              PC                Routine            Line        Source             
test5              000000000040E28E  Unknown               Unknown  Unknown
test5              000000000042A9F9  Unknown               Unknown  Unknown
test5              0000000000407821  MAIN__                    131  test5.f90
test5              0000000000402ABE  Unknown               Unknown  Unknown
libc-2.27.so       00007F15519BBB97  __libc_start_main     Unknown  Unknown
test5              00000000004029AA  Unknown               Unknown  Unknown

Что я делаю не так?


person Eenoku    schedule 08.06.2018    source источник
comment
Пожалуйста, скомпилируйте с флагами отладки (-g -traceback -check), чтобы получить значимые обратные трассировки. Сейчас и на будущие вопросы. Также для себя, чтобы вам было легче злиться.   -  person Vladimir F    schedule 08.06.2018
comment
@VladimirF Добавлено улучшенное сообщение об ошибке.   -  person Eenoku    schedule 08.06.2018
comment
Хорошо, теперь я нашел ваш комментарий ! ERROR, но его было трудно найти.   -  person Vladimir F    schedule 08.06.2018
comment
Вы используете определенный вывод, но не определенный ввод? То есть, почему вы используете read(123) t%num, t%num2, а не read(123) t, как вы write(123) t?   -  person francescalus    schedule 08.06.2018
comment
@francescalus Вы совершенно правы, в основном это была опечатка или, лучше сказать, глупая ошибка. Напишите, пожалуйста, ваш комментарий в качестве ответа, чтобы я мог его принять.   -  person Eenoku    schedule 09.06.2018
comment
Извините, я действительно ввел вас в заблуждение. Я объясню в ответ.   -  person francescalus    schedule 09.06.2018
comment
Это действительно дубликат вашего более нового вопроса. Я не могу закрыть как дубликат из-за моего предыдущего голосования за опечатку. read(123) t работает по той же причине, что и ошибка в этом вопросе. read(123) t%num, t%num2 терпит неудачу, потому что соответствующий write(123) t записывает только это значение, как будто t имеет тип a.   -  person francescalus    schedule 09.06.2018