使用定义的输入过程从Fortran中的二进制文件读取错误值 [英] Reading bad values from binary file in Fortran with a defined input procedure
问题描述
我试图编写一个简单的代码,该代码将具有相同父抽象类的某些对象带入一个二进制文件中,然后将它们读回。
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屋!