Avoiding the GOTO paradigm in Fortran FORMAT when reading/writing

Viewed 121

At the university, the professor teaching us Fortran, gave us the following code:

     program example
     integer year, month, day, inst, kind, ozone
     real time
     open(unit=1,file='C:\261.dat')
     read(1,1000) year, month, day, inst, kind, ozone, time
     close(1)  
1000 format(i4,1x,i2,1x,i2,1x,i1,1x,i1,1x,i3,1x,f8.3)
     end

In this code, the line indexed with 1000 specifies the particular input format. Isn't it something like a GOTO logic? And if yes, what's the most appropriate way to avoid it, in the context of Fortran?

2 Answers

In a formatted data transfer statement there are three ways to specify the format to use (Fortran 2018 R1215):

  • referencing a labelled FORMAT statement
  • using a (default) character expression
  • with a * (for list-directed formatting)

For example (using a PRINT statement for clarity):

1000 FORMAT (I0)

print 1000, 1     ! Pointing to a FORMAT statement
print '(I0)', 1   ! Literal constant: one form of a character expression
print *, 1        ! List-directed formatting

end

In none of these is the format specification functionally like a GO TO statement.

A GO TO statement changes the flow of execution whereas in the format specification execution remains at the data transfer statement, and then continues to the next statement.

Specifying a label for the format doesn't transfer execution control to that statement, it simply says "use the format given by the statement 1000". This is conceptually like how

character(*), parameter :: CHAR_FMT='(I0)'
print CHAR_FMT, 1
end

says "use the character object CHAR_FMT (which is declared/defined elsewhere)" as the format.

You'll find may objections to FORMAT statements and (reasonable) suggestions for alternatives, but no objection to using a FORMAT statement is based on "like a GO TO". (And, of course, GO TO statements are not inherently evil.)


Format specifications can be contrasted with the err= and end= and eor= specifiers: these functionally are like GO TO statements:


1 read(unit, fmt, err=10, end=20, eor=20) x
...
! COME FROM 1
20 continue
...

return
! COME FROM 1
10 ERROR STOP "Error in the read"

Such jump-like flow can be alternatively managed with IOSTAT control:

read(unit, fmt, iostat=iostat) x
if (iostat...) ...

You can avoid using format labels by instead using format strings, as

program example
  integer year, month, day, inst, kind, ozone
  real time
  
  open(unit=1,file='C:\261.dat')
  read(1,'(i4,1x,i2,1x,i2,1x,i1,1x,i1,1x,i3,1x,f8.3)') year, month, day, inst, kind, ozone, time
  close(1)
end

you can treat the format string as a regular character variable, as

program example
  integer year, month, day, inst, kind, ozone
  real time
  character(42) :: format
  
  open(unit=1,file='C:\261.dat')
  format = '(i4,1x,i2,1x,i2,1x,i1,1x,i1,1x,i3,1x,f8.3)'
  read(1,format) year, month, day, inst, kind, ozone, time
  close(1)
end

This allows you to pass formats around your code just like any other variable, and also allows you to generate and modify formats at runtime.

Related