GCC6.3.0版gfortran编译Fortran代码遇ALLOCATABLE组件IO错误求解决
Got it, let's tackle this issue head-on. The error you're seeing happens because gfortran 6.3.0 doesn't support direct I/O (read/write) of derived types with allocatable components unless you explicitly define custom input/output procedures. Newer Intel Fortran versions handle this automatically (thanks to better support for Fortran 2003+ standards), but we need to adjust the code to play nice with the older GCC toolchain.
Here are two reliable, compiler-compatible fixes:
Option 1: Implement User-Defined I/O Procedures (Standard Fortran Approach)
This is the cleanest, most scalable solution—it aligns with Fortran standards and works across all compliant compilers. You'll add custom read/write routines directly to your TCosmoTheoryParams type definition.
Step 1: Update the Derived Type Definition
Add bindings for custom read/write procedures to your type:
type :: TCosmoTheoryParams ! Your existing components (example): real, allocatable :: HubbleParam(:) integer :: NumCosmoModels logical :: UseDarkEnergy contains ! Bind custom procedures for formatted I/O procedure :: write_tcp => write_TCosmoTheoryParams procedure :: read_tcp => read_TCosmoTheoryParams generic :: write(formatted) => write_tcp generic :: read(formatted) => read_tcp ! Add these if you're using unformatted (binary) I/O: ! generic :: write(unformatted) => write_tcp ! generic :: read(unformatted) => read_tcp end type TCosmoTheoryParams
Step 2: Write the Custom Read/Write Routines
These routines handle each component explicitly, including allocatable arrays:
! Custom write procedure for TCosmoTheoryParams subroutine write_TCosmoTheoryParams(this, unit, iotype, v_list, iostat, iomsg) class(TCosmoTheoryParams), intent(in) :: this integer, intent(in) :: unit character(*), intent(in) :: iotype integer, intent(in) :: v_list(:) integer, intent(out) :: iostat character(*), intent(inout) :: iomsg ! Write non-allocatable components first write(unit, *, iostat=iostat, iomsg=iomsg) this%NumCosmoModels, this%UseDarkEnergy if (iostat /= 0) return ! Handle allocatable array: write size first, then data if (allocated(this%HubbleParam)) then write(unit, *, iostat=iostat, iomsg=iomsg) size(this%HubbleParam), this%HubbleParam else ! Use a sentinel value (-1) to mark unallocated arrays write(unit, *, iostat=iostat, iomsg=iomsg) -1 end if end subroutine write_TCosmoTheoryParams ! Custom read procedure for TCosmoTheoryParams subroutine read_TCosmoTheoryParams(this, unit, iotype, v_list, iostat, iomsg) class(TCosmoTheoryParams), intent(inout) :: this integer, intent(in) :: unit character(*), intent(in) :: iotype integer, intent(in) :: v_list(:) integer, intent(out) :: iostat character(*), intent(inout) :: iomsg integer :: arr_size ! Read non-allocatable components read(unit, *, iostat=iostat, iomsg=iomsg) this%NumCosmoModels, this%UseDarkEnergy if (iostat /= 0) return ! Read array size, then allocate and read data read(unit, *, iostat=iostat, iomsg=iomsg) arr_size if (iostat /= 0) return if (arr_size > 0) then ! Deallocate existing array if needed if (allocated(this%HubbleParam)) deallocate(this%HubbleParam, stat=iostat) if (iostat /= 0) then iomsg = "Failed to deallocate HubbleParam in TCosmoTheoryParams" return end if ! Allocate new array allocate(this%HubbleParam(arr_size), stat=iostat) if (iostat /= 0) then iomsg = "Failed to allocate HubbleParam in TCosmoTheoryParams" return end if ! Read array data read(unit, *, iostat=iostat, iomsg=iomsg) this%HubbleParam else ! Mark array as unallocated if (allocated(this%HubbleParam)) deallocate(this%HubbleParam, stat=iostat) end if end subroutine read_TCosmoTheoryParams
Step 3: Keep Your Original Read/Write Calls
Your existing lines:
read(F%Unit) FileSettings%TCosmoTheoryParams Write(F%Unit) CosmoSettings%TCosmoTheoryParams
will now work as-is—gfortran will automatically call your custom procedures instead of trying to handle the type directly.
Option 2: Manual Component-by-Component I/O (Quick Fix)
If you don't want to modify the type definition, you can manually read/write each component of the derived type. This is simpler for small types but less maintainable if the type structure changes.
Replace Your Write Call
Instead of writing the entire type, write each component explicitly:
! Replace Write(F%Unit) CosmoSettings%TCosmoTheoryParams with (CosmoSettings%TCosmoTheoryParams) write(F%Unit) NumCosmoModels, UseDarkEnergy if (allocated(HubbleParam)) then write(F%Unit) size(HubbleParam), HubbleParam else write(F%Unit) -1 end if end with
Replace Your Read Call
Similarly, read each component one by one:
! Replace read(F%Unit) FileSettings%TCosmoTheoryParams integer :: arr_size with (FileSettings%TCosmoTheoryParams) read(F%Unit) NumCosmoModels, UseDarkEnergy read(F%Unit) arr_size if (arr_size > 0) then if (allocated(HubbleParam)) deallocate(HubbleParam) allocate(HubbleParam(arr_size)) read(F%Unit) HubbleParam else if (allocated(HubbleParam)) deallocate(HubbleParam) end if end with
Why This Works
Newer Intel Fortran versions implement automatic derived type I/O for types with allocatable components (per Fortran 2003+ specs), but gfortran didn't fully support this until versions 8 and later. By explicitly handling the allocatable components in your code, you bypass gfortran 6.3.0's limitation.
内容的提问来源于stack exchange,提问作者johnhenry

