Internal Files, Namelist and Non-Advancing I/O
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against Fortran 2023 (ISO/IEC 1539-1:2023, J3/23-007r1) and was checked on 2026-10-19. Every
example was compiled with gfortran -std=f2023 -Wall -Wextra -pedantic -fimplicit-none -fcheck=all (GNU Fortran 16.2)
and run, and the examples were also built and run with LLVM Flang 23; the output shown is real output, and where the two
compilers print different things both are shown. Examples that are deliberately wrong, or that expose a difference between
the compilers, are labelled as such and show the real diagnostics. The rules are in these places in the standard: internal
files are 12.4, the control information list of a data transfer statement is 12.6.2 (advance= is 12.6.2.4, size= is
12.6.2.16), advancing and nonadvancing transfer is 12.3.4.2, the error, end-of-record and end-of-file conditions with
iostat=, iomsg=, err=, end= and eor= are 12.11, list-directed formatting is 13.10, namelist formatting is 13.11 and
the namelist statement is 8.9. Annex C.8.2 has the standard’s own notes on nonadvancing transfer.
Most of Fortran’s input and output is formatted: a format specification says how each value is edited into characters. This page covers four ways of doing formatted transfer without writing a format for every item, or without a file at all:
| Tool | What it does | Typical use in the running example, heatflow |
|---|---|---|
Internal file |
a |
building a label such as |
List-directed I/O |
the value types, not a format, drive the editing; values are separated by blanks, commas or slashes |
reading a few numbers from a string; quick |
Namelist I/O |
named values, in any order, with defaults kept for what is not mentioned |
the configuration file |
Non-advancing I/O |
a record is read or written by several statements, and the length of an input record is found out while reading |
prompts, a CSV row built item by item, reading a line of unknown length |
The format side (the edit descriptors i0, f8.3, es12.4, g0, a, /, : and the rest) is in
Format Specifications and Edit Descriptors,
units, open and file connection are in
Input/Output: Units and Files, user-defined derived-type
I/O and asynchronous transfer are in
Derived-Type and Asynchronous I/O, and the string
intrinsics (trim, adjustl, index, scan, F2023 split and tokenize) are in
Characters and Strings. This page uses the namelist file of
the running example, which is read by read_config in the module heatflow_config; the module is described in
Modules and Submodules.
Internal files
An internal file "provides a means of transferring and converting data from internal storage to internal storage"
(12.4). The unit of the data transfer statement is a character variable instead of a unit number, and no open, close
or inquire is involved. Writing to the variable converts values to text; reading from it converts text to values, with
the same editing rules as a file.
The rules of 12.4
| Rule | Detail |
|---|---|
The file is a character variable |
of default, ASCII or ISO 10646 kind, and not an array section with a vector subscript. A character constant or other expression is not a valid unit (see below) |
A scalar is one record |
its length is the length of the variable; a character array is a sequence of records, one per element, in array element order, all of the same length |
Writing pads with blanks |
if fewer characters are written than the record holds, the rest is filled with blanks; writing more than the record holds is not allowed (see the overrun section) |
Always positioned at the first record |
every data transfer to an internal file starts at the beginning of the first record (except child data transfers, see the derived-type I/O page) |
Sequential formatted access only |
only |
Reading needs defined text |
a record shall be read only if it is defined, so read a variable that has been assigned |
Connection modes take their defaults |
blank mode, pad mode, decimal mode and the rest behave as for a unit opened without those keywords (12.4) |
An internal file needs a fmt= or an nml= (C1221). The specifiers that make sense without a file are allowed:
iostat=, iomsg=, err=, end=, decimal=, blank=, pad=, round=, sign= and delim= (some only for input or
only for output, C1212 and C1213). advance= is not allowed with an internal file (C1223), and neither are rec= and
pos= (C1220) or asynchronous='yes' (C1226).
Converting values to text and back
The idiom is: write into a buffer that is longer than any value, then use len_trim or trim; read from the buffer or from
any character variable or substring. A substring is a valid internal file, which is useful for reading a field out of a longer
record.
program internal_write_read
use, intrinsic :: iso_fortran_env, only: int32, real64
implicit none
character(len=40) :: line
character(len=8) :: field
integer(int32) :: nx
real(real64) :: alpha
integer :: stat
! Internal write: the variable is the "file", the record is blank padded.
write (line, '(a, i0, a, f5.2)') 'nx=', 41, ' alpha=', 1.0_real64
print '(3a)', '[', line, ']'
print '(2(a, i0))', 'len=', len(line), ' len_trim=', len_trim(line)
! A substring is a legal internal file too.
field = ' 41'
read (field, *, iostat=stat) nx
print '(a, i0, a, i0)', 'nx=', nx, ' stat=', stat
! Internal read with an explicit format; blanks are not zeros by default.
read (line(14:18), '(f5.2)', iostat=stat) alpha
print '(a, f5.2, a, i0)', 'alpha=', alpha, ' stat=', stat
end program internal_write_read
Both compilers print the same:
[nx=41 alpha= 1.00 ]
len=40 len_trim=17
nx=41 stat=0
alpha= 1.00 stat=0
Notes on the example: the record is the whole 40-character variable, so the text ends in blanks (len_trim is 17, the length
of nx=41 alpha= 1.00); the field width of f5.2 gives the leading blank in alpha= 1.00, so i0 and f0.d are the usual
choice when the text must not be padded; and read (field, *) is a list-directed read, which ignores the leading blanks of
field.
The same technique converts strings to numbers and back inside a generic to_string, as shown in
Characters and Strings.
Arrays of records
A character array is a file of as many records as it has elements. A write that has more items than the format has
descriptors starts a new record by format reversion (the format is reused from its start, in a new record), and a slash
edit descriptor does the same. A list-directed read continues into the next record when it needs more values, because the
end of a record counts as a blank.
program array_records
use, intrinsic :: iso_fortran_env, only: int32
implicit none
character(len=12) :: rec(3)
integer(int32) :: a, b, c
integer :: i
! Format reversion starts a new record: three items, one i0 item per record.
write (rec, '(i0)') 10, 20, 30
do i = 1, size(rec)
print '(a, i0, 3a)', 'record ', i, ' [', rec(i), ']'
end do
! A list-directed read continues into the next record when it needs more values.
read (rec, *) a, b, c
print '(a, 3(1x, i0))', 'read back:', a, b, c
! Two items per record: the format has two items, so reversion starts a new record after each pair.
rec = ''
write (rec, '(i0, 1x, i0)') 1, 2, 3, 4
do i = 1, size(rec)
print '(a, i0, 3a)', 'record ', i, ' [', rec(i), ']'
end do
end program array_records
Both compilers print the same:
record 1 [10 ]
record 2 [20 ]
record 3 [30 ]
read back: 10 20 30
record 1 [1 2 ]
record 2 [3 4 ]
record 3 [ ]
The unused third record of the second write is blank because the program assigned rec = '' first; a record that was not
written is not defined, so a program should not read it.
Overruns
An internal write shall not put more characters into a record than the record can hold. The standard says "shall", so the
program is not conforming; what happens is the processor’s choice, and the two compilers choose differently. With
iostat= both report the condition and do not stop; without it both terminate the program.
program overrun
implicit none
character(len=6) :: buffer
integer :: stat
character(len=80) :: msg
write (buffer, '(a)', iostat=stat, iomsg=msg) 'too long for it'
print '(a, i0)', 'stat=', stat
print '(3a)', 'msg=[', trim(msg), ']'
end program overrun
GNU Fortran 16.2, then LLVM Flang 23:
stat=-2
msg=[End of record]
stat=1002
msg=[Excessive output to fixed-size record]
GNU Fortran reports the overrun as an end-of-record condition: the status is negative (iostat_eor is -2 on both
compilers) and the message is End of record. LLVM Flang reports a positive error status (1002; do not rely on the number)
with the message Excessive output to fixed-size record. The contents of the variable after the failed write are
unspecified, so the portable test is "was the status non-zero", and the safe code makes the buffer large enough, or measures
first. Without iostat= the
statement terminates the program. For the three-line program 03b_overrun_fatal (a bare write (buffer, '(a)') 'too long for it') the
output is, from GNU Fortran 16.2 (the backtrace is shortened) and then from LLVM Flang 23:
At line 5 of file 03b_overrun_fatal.f90
Fortran runtime error: End of record
Error termination. Backtrace:
fatal Fortran runtime error(/work/03b_overrun_fatal.f90:5): Excessive output to fixed-size record
Aborted
The unit must be a variable
A character constant cannot be an internal file. It is tempting to write read ('42', *) n, but the unit has to be a
variable, because the unit of an input/output statement is either a unit number, *, or a variable. Assign the text to a
variable first. Both compilers reject the constant at compile time:
program nonconst_unit
implicit none
integer :: n
read ('42', *) n
print '(i0)', n
end program nonconst_unit
GNU Fortran 16.2:
16_nonconst_unit.f90:5:8:
5 | read ('42', *) n
| 1
Error: UNIT specification at (1) must be an INTEGER expression or a CHARACTER variable
LLVM Flang 23:
error: Semantic errors in 16_nonconst_unit.f90
16_nonconst_unit.f90:5:9: error: I/O unit must be a character variable or a scalar integer expression, but is an expression of type CHARACTER(KIND=1,LEN=2_8)
read ('42', *) n
^^^^
Deferred-length internal files (Fortran 2023)
Before Fortran 2023 the character variable of an internal write had to be long enough, which is why the idioms above
use a generous fixed buffer. Fortran 2023 lets the unit of a write be a deferred-length allocatable scalar: it is
assigned the characters written by intrinsic assignment, "allocating or reallocating to have length equal to the number of
characters written if necessary" (12.4), and the same release allows a deferred-length allocatable iomsg= variable
(12.11.6). Both are listed in the Introduction of the standard under "Input/output". The example below uses it:
! Fortran 2023: a deferred-length allocatable scalar internal file in WRITE is allocated
! to the length of the record written. Not implemented by GNU Fortran 16.2 or LLVM Flang 23.
program internal_write_f2023
implicit none
character(len=:), allocatable :: line
write (line, '(a, i0, a, f6.2)') 'nx=', 41, ' alpha=', 1.0
print '(a, i0, 3a)', 'len=', len(line), ' [', line, ']'
end program internal_write_f2023
Neither GNU Fortran 16.2 nor LLVM Flang 23 implements it. The variable stays unallocated and the compiler reports an
end-of-file error (GNU Fortran, after a -Wmaybe-uninitialized warning) or an overrun (Flang):
15_internal_write_f2023.f90:7:60:
7 | write (line, '(a, i0, a, f6.2)') 'nx=', 41, ' alpha=', 1.0
| ^
Warning: '.line' may be used uninitialized [-Wmaybe-uninitialized]
At line 7 of file 15_internal_write_f2023.f90
Fortran runtime error: End of file
fatal Fortran runtime error(/work/15_internal_write_f2023.f90:7): Internal write overran available records
Aborted
Until the compilers catch up, write into a fixed-length buffer and assign trim(buffer) to the allocatable string, as the
convert module in Characters and Strings does. That page also
shows the same limitation for iomsg= and errmsg=.
List-directed I/O
In list-directed I/O the format is *: print *, x, write (unit, *) x or read (unit, *) x. The editing is chosen by the
type of each item instead of by an edit descriptor, and the values in the record are free field: they are separated by
blanks, commas (semicolons when the decimal mode is comma) or slashes (13.10.2).
List-directed input
The rules for input (13.10.2 and 13.10.3) are short, and every one of them is a source of surprises:
| Situation | Rule |
|---|---|
Separators |
a comma, a slash, or one or more blanks between two nonblank values; consecutive blanks count as one; the end of a record counts as a blank, so values can continue on the next record |
Values |
a literal constant of the kind of the item (no kind suffix), optionally signed for numbers, in any form acceptable to the corresponding edit descriptor: for a real |
Character values |
delimited by apostrophes or quotes, in which case they may contain blanks, commas and slashes. An undelimited value (it may not start with a quote or with digits followed by an asterisk) ends at the first blank, comma, slash or end of record, and quotes inside it are not doubled |
Null value |
two consecutive commas (or a comma at the start of the list) leave the corresponding item unchanged; this includes an item that is undefined |
Repeat counts |
|
The slash |
a slash ends the input statement; the remaining items of the list keep their previous values, as if null values had been supplied |
Too few values |
input continues on the next record; if the file or string runs out before the list is satisfied, an end-of-file condition occurs (12.11.3), and the items become undefined |
Too many values |
the extra values are ignored: the rest of the record is skipped by an advancing |
Invalid value |
an error condition; |
program list_directed_input
use, intrinsic :: iso_fortran_env, only: int32, real64
implicit none
character(len=48) :: text
character(len=2) :: lines(2)
integer(int32) :: n, m
real(real64) :: x, y
logical :: flag
complex(real64) :: z
character(len=12) :: word, phrase
integer :: stat
! Blanks and commas separate values; a quoted string may contain both.
text = '7 8.5, T (1.0,2.0) abc "two words, one"'
read (text, *) n, x, flag, z, word, phrase
print '(a, i0, a, f0.2, a, l1)', 'n=', n, ' x=', x, ' flag=', flag
print '(a, 2(f0.1, 1x))', 'z=', z
print '(3a)', 'word=[', word, ']'
print '(3a)', 'phrase=[', phrase, ']'
! Null values keep the previous value of the item.
n = -1; m = -1; x = -1.0_real64; y = -1.0_real64
text = '5, , 2.5, ,'
read (text, *) n, m, x, y
print '(a, 2(1x, i0), 2(1x, f0.1))', 'null values:', n, m, x, y
! r*c repeats a value, r* repeats a null value; the slash ends the statement.
n = -1; m = -1; x = -1.0_real64; y = -1.0_real64
text = '2*3 / 9.0 9.0'
read (text, *) n, m, x, y
print '(a, 2(1x, i0), 2(1x, f0.1))', 'repeat and slash:', n, m, x, y
! The end of a record is a separator too, so a list continues on the next record.
lines = [character(len=2) :: '1', '2']
read (lines, *) n, m
print '(a, 2(1x, i0))', 'two records:', n, m
! An invalid value is an error condition (iostat > 0); running out of records is end-of-file.
text = '12x'
read (text, *, iostat=stat) n
print '(a, l1)', 'bad integer is an error: ', stat > 0
text = ''
read (text, *, iostat=stat) n
print '(a, l1)', 'empty record is end-of-file: ', stat < 0
end program list_directed_input
Both compilers print the same:
n=7 x=8.50 flag=T
z=1.0 2.0
word=[abc ]
phrase=[two words, o]
null values: 5 -1 2.5 -1.0
repeat and slash: 3 3 -1.0 -1.0
two records: 1 2
bad integer is an error: T
empty record is end-of-file: T
Things worth noticing in the output: the string "two words, one" was truncated to 12 characters because phrase has
length 12 (assignment rules of an intrinsic assignment, not an error); the null values left m and y at -1; the repeat
count 2*3 filled the two integers; and the slash stopped the read before 9.0 9.0, so the reals kept their old values.
A blank internal file gives an end-of-file condition, not an error, because the list needs a value and there is no next
record, which is why reading a blank string with iostat= gives a negative status.
A list-directed read is the shortest way to parse a number in a string, but it is lenient: read (text, *) x is happy with
'0.25 trailing' and with '0.25,1', and an explicit format with iostat= is stricter. Both are covered in
Characters and Strings.
List-directed output
The standard describes the form of list-directed output, not its layout (13.10.4): the values are separated by one or more
blanks (or by a comma or semicolon, optionally surrounded by blanks), every record starts with a blank, integers are written as
if with Iw, reals as if with 0PFw.d or 1PEw.d Ee depending on their magnitude within a processor-dependent range,
logicals as T or F, complex values in parentheses, and character values without delimiters unless the delim= mode says
otherwise. The widths and digits are "reasonable processor-dependent values", so no two compilers agree, and a program that
parses its own print * output depends on one compiler. Two adjacent undelimited character values are not separated at all,
which is why print *, 'text', 'more' prints textmore.
program list_directed_output
use, intrinsic :: iso_fortran_env, only: int32, real32, real64
implicit none
character(len=80) :: line
integer :: i
! The standard fixes only the form of the values, not the widths or digits (13.10.4).
print *, 42_int32, -7_int32
print *, 0.5_real32, 0.5_real64
print *, 1.0_real64 / 3.0_real64
print *, 100.0_real64, 1.0e-5_real64, 1.0e10_real64
print *, 0.0_real64
print *, .true., .false.
print *, (1.5_real64, -2.0_real64)
print *, 'text', 'more'
! Repeated values: the processor may print r*c.
print *, 1, 1, 1, 2
print *, [(0.0_real64, i = 1, 4)]
! Every record starts with a blank; internal output shows it.
write (line, *) 'x=', 3
print '(3a, i0)', '[', line(1:12), '] len_trim=', len_trim(line)
! delim= changes how character values are written: a quote delimiter doubles inner quotes.
write (line, *, delim='quote') 'say "hi"', 'ok'
print '(3a)', '[', trim(line), ']'
write (line, *, delim='apostrophe') 'it''s', 'ok'
print '(3a)', '[', trim(line), ']'
end program list_directed_output
GNU Fortran 16.2, then LLVM Flang 23:
42 -7
0.500000000 0.50000000000000000
0.33333333333333331
100.00000000000000 1.0000000000000001E-005 10000000000.000000
0.0000000000000000
T F
(1.5000000000000000,-2.0000000000000000)
textmore
1 1 1 2
0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
[ x= ] len_trim=15
[ "say ""hi""" "ok"]
[ 'it''s' 'ok']
42 -7
.5 .5
.3333333333333333
100. 1.E-05 10000000000.
0.
T F
(1.5,-2.)
textmore
1 1 1 2
0. 0. 0. 0.
[ x= 3 ] len_trim=5
[ "say ""hi""" "ok"]
[ 'it''s' 'ok']
The differences are large. GNU Fortran prints every integer in a field of fixed width and every real with all the digits of
its kind in a wide field; Flang prints short forms with a single blank between values and omits leading zeros (.5) and
trailing zeros (100., 0.). Neither is wrong. The consequences:
-
Use list-directed output for diagnostics only. For files, reports and anything another program reads, use an explicit format (
es12.5,f8.3,g0,i0). -
The first column is a blank. Each record starts with a blank (13.10.4), as the internal file shows (
[ x=...); the standard does not give the first column any special meaning (the compatibility notes in 4.3.6 say that earlier standards did, as printer carriage control). -
Repeat counts are optional. The processor "has the option" of producing
r*cfor identical successive values; neither compiler does here (print *, 1, 1, 1, 2prints four values), but a reader of list-directed data must accept them. -
The output of a real zero changed in the standard. The compatibility list of the standard (4.3.6, Fortran 95) notes that the document "specifies a different output format for real zero values in list-directed and namelist output", and the two compilers show two forms (
0.0000000000000000and0.). -
delim=is the way to get quoted strings. Withdelim='quote'ordelim='apostrophe', character values are delimited, are separated from the next value, and have any inner delimiter doubled, which makes the output readable by a list-directedread. The default,none, is not. -
GNU Fortran has an environment variable for the separator.
GFORTRAN_LIST_SEPARATORsets the separator of list-directed output (any number of spaces and at most one comma; the default is a single space), but it is a runtime switch of one compiler, not part of the language. The standard way is thedecimal=mode (decimal='comma'makes the separator a semicolon).
Namelist I/O
A namelist group gives a name to a list of variables. A read or write that names the group transfers all of them as
name = value pairs, so the data are self-describing, order does not matter, variables can be left out, and the file can carry
comments. That is exactly what a configuration file needs, and it is why heatflow reads heatflow.nml:
&heatflow
nx = 21
ny = 21
lx = 1.0
ly = 1.0
alpha = 1.0
dt = 5.0e-5
hot_temperature = 100.0
boundary_value = 0.0
max_steps = 2000
tolerance = 1.0e-8
bc = 1
solver = 'ftcs'
output = 'heatflow.csv'
/
The namelist statement (8.9) declares the group; it follows the declarations of the variables it names. In heatflow_config
the group is local to read_config, which copies the defaults of config_t into local variables, reads the group from the
file, and copies the result back only on success, so an error leaves the caller’s configuration untouched:
integer(ip) :: nx, ny, max_steps
integer :: bc, unit
real(dp) :: lx, ly, alpha, dt, hot_temperature, boundary_value, tolerance
character(len=16) :: solver
character(len=64) :: output
namelist /heatflow/ nx, ny, lx, ly, alpha, dt, hot_temperature, &
boundary_value, max_steps, tolerance, bc, solver, output
nx = cfg%nx; ny = cfg%ny; lx = cfg%lx; ly = cfg%ly
! ... the other defaults are copied the same way ...
msg = ''
open (newunit=unit, file=file, status='old', action='read', iostat=stat, iomsg=msg)
if (stat /= 0) return
read (unit, nml=heatflow, iostat=stat, iomsg=msg)
close (unit)
if (stat /= 0) return
A complete program that uses it, with the module from the running example (compiled together with heatflow_kinds,
heatflow_constants, heatflow_boundary and heatflow_config):
program read_config_demo
use heatflow_boundary, only: boundary_name
use heatflow_config, only: config_t, read_config
implicit none
type(config_t) :: cfg
integer :: stat
character(len=120) :: msg
call read_config('heatflow.nml', cfg, stat, msg)
print '(a, i0, 3a)', 'stat=', stat, ' [', trim(msg), ']'
print '(a, i0, a, i0)', 'grid ', cfg%nx, ' x ', cfg%ny
print '(a, f0.1, a, es9.2)', 'hot=', cfg%hot_temperature, ' dt=', cfg%dt
print '(3a, i0)', 'solver=', trim(cfg%solver), ' steps=', cfg%max_steps
print '(2a)', 'boundary=', boundary_name(cfg%bc)
call read_config('missing.nml', cfg, stat, msg)
print '(a, l1, 3a)', 'missing file: stat/=0 is ', stat /= 0, ' [', trim(msg), ']'
end program read_config_demo
GNU Fortran 16.2, then LLVM Flang 23. The only difference is the text of the iomsg= message for the missing file:
stat=0 []
grid 21 x 21
hot=100.0 dt= 5.00E-05
solver=ftcs steps=2000
boundary=dirichlet
missing file: stat/=0 is T [Cannot open file 'missing.nml': No such file or directory]
stat=0 []
grid 21 x 21
hot=100.0 dt= 5.00E-05
solver=ftcs steps=2000
boundary=dirichlet
missing file: stat/=0 is T [No such file or directory]
The bc variable is a plain integer in the namelist because the standard forbids enumeration types as namelist group
objects (constraint C8109 of 8.9); read_config converts it to the bc_kind integer of the enumerators afterwards.
The namelist statement
| Rule | Detail |
|---|---|
Syntax |
|
Group objects |
variable names that are accessible by use or host association or whose type, kind and rank are declared before the statement; they shall not be assumed-size arrays (C8108), nor of enumeration type, nor have a direct component of enumeration type (C8109) |
Use association |
the group name in a |
Several groups |
one variable can belong to more than one group |
Output order |
the order of the list; a variable listed twice is written twice |
A group cannot be mixed with other items |
a data transfer statement with |
Namelist input
The form of the input (13.11.3): optional blanks and comments, & immediately followed by the group name, one or more
blanks, zero or more name = value subsequences separated by value separators, and a slash. The group name and the object
names are matched without regard to case.
| Situation | Rule |
|---|---|
Order and omission |
subsequences can come in any order, any of them can be missing, and one can appear more than once; what is not mentioned keeps its value |
Designators |
a name, an array element or section with literal integer subscripts, a substring, or a component of a derived type ( |
Arrays |
|
Scalars |
at most one value after the equals |
Values and separators |
as in list-directed input: blanks or commas separate, |
Null values |
|
Comments |
a |
The slash |
ends the namelist input; anything after it, on the same record or later, is not read |
Real and complex |
a real value is a numeric input field "assumed to have no fractional digits unless a decimal symbol appears", so |
The following program reads a namelist from an array of character records (a namelist read from an internal file is legal, because an internal file must have a format or a namelist group, C1221), then writes the group to the standard output and to another internal file.
program namelist_forms
use, intrinsic :: iso_fortran_env, only: int32, real64
implicit none
integer(int32) :: nx = 21, ny = 21
real(real64) :: alpha = 1.0_real64
real(real64) :: probe(4) = 0.0_real64
logical :: verbose = .false.
character(len=8) :: solver = 'ftcs'
complex(real64) :: z = (0.0_real64, 0.0_real64)
character(len=100) :: text(3)
character(len=200) :: out(12)
integer :: stat, i
character(len=100) :: msg
namelist /run/ nx, ny, alpha, probe, verbose, solver, z
! Input: any order, case-insensitive, partial, array sections, a repeat count, a comment and a slash.
text(1) = '&RUN ny = 41, SOLVER = ''jacobi'', probe(2:3) = 2*1.5, verbose = t ! a comment'
text(2) = ' Z = (1.0, -2.0) alpha = 0.25'
text(3) = '/ this text after the slash is never read'
read (text, nml=run, iostat=stat, iomsg=msg)
print '(a, i0)', 'stat=', stat
print '(2(a, i0), a, f4.2, 2a)', 'nx=', nx, ' ny=', ny, ' alpha=', alpha, ' solver=', trim(solver)
print '(a, 4(1x, f3.1))', 'probe:', probe
print '(a, l1, a, 2f5.1)', 'verbose=', verbose, ' z=', z
! Output: upper-case names, the group name, one record per start of a value list, a closing slash.
write (*, nml=run)
! The same output into an internal file, with quote delimiters for strings.
out = ''
write (out, nml=run, delim='quote')
do i = 1, size(out)
if (len_trim(out(i)) > 0) print '(a, i0, 3a)', 'record ', i, ' [', trim(out(i)), ']'
end do
end program namelist_forms
GNU Fortran 16.2, then LLVM Flang 23:
stat=0
nx=21 ny=41 alpha=0.25 solver=jacobi
probe: 0.0 1.5 1.5 0.0
verbose=T z= 1.0 -2.0
&RUN
NX=21 ,
NY=41 ,
ALPHA= 0.25000000000000000 ,
PROBE= 0.0000000000000000 , 2*1.5000000000000000 , 0.0000000000000000 ,
VERBOSE=T,
SOLVER="jacobi ",
Z=(1.0000000000000000,-2.0000000000000000),
/
record 1 [ &RUN]
record 2 [ NX=21 ,]
record 3 [ NY=41 ,]
record 4 [ ALPHA= 0.25000000000000000 ,]
record 5 [ PROBE= 0.0000000000000000 , 2*1.5000000000000000 , 0.0000000000000000 ,]
record 6 [ VERBOSE=T,]
record 7 [ SOLVER="jacobi ",]
record 8 [ Z=(1.0000000000000000,-2.0000000000000000),]
record 9 [ /]
stat=0
nx=21 ny=41 alpha=0.25 solver=jacobi
probe: 0.0 1.5 1.5 0.0
verbose=T z= 1.0 -2.0
&RUN NX= 21,NY= 41,ALPHA= .25,PROBE= 0. 1.5 1.5 0.,VERBOSE= T,SOLVER= jacobi
,Z= (1.,-2.)/
record 1 [ &RUN NX= 21,NY= 41,ALPHA= .25,PROBE= 0. 1.5 1.5 0.,VERBOSE= T,SOLVER= "jacobi ",Z= (1.,-2.)/]
Source: J3/23-007r1 clauses 8.9 (NAMELIST statement), 12.4 (Internal files) and 13.11 (Namelist formatting)
The read shows the input rules at work: the group name &RUN and the object names SOLVER and Z were written in
upper case and matched anyway; the array section probe(2:3) = 2*1.5 used a repeat count; verbose = t was followed by a
comment; alpha = 0.25 was on a second record; and the slash on the third record ended the input, so the text after it was never read.
nx was not mentioned and kept 21.
Namelist output
Namelist output (13.11.4) has the form of a namelist input record: &GROUP, then NAME=value pairs in the order of the
namelist statement, then a slash. The names are in upper case and no comments are produced. The values are edited as for
list-directed output (13.11.4.2), so the layout is as processor dependent as in the previous section: GNU Fortran writes one
object per record with wide numeric fields and a repeat count for identical neighbours (2*1.5000...), Flang writes everything
on one long record with the shortest representation. (GNU Fortran starts the first record at column 1 when the unit is the
standard output; the internal file shows the usual leading blank.)
Two points matter for round trips:
-
The default
delim=nonewrites strings without delimiters, so a string with a blank, comma or slash is not read back correctly. Open the unit withdelim='quote'(orapostrophe) or putdelim='quote'in thewritestatement, as the secondwriteof the example does. (Namelist output is "suitable for input, except for character output", 13.11.4.1.) -
A character variable is written with its full length, blanks included (
"jacobi "), and read back the same way.
Derived types and public groups
For a derived-type variable the designator in the input can be a component, grid%nx = 41, or the whole variable, in which case
the values are assigned to the ultimate components in order, as if the variable were expanded into a list of scalar items
(13.11.3.2). A namelist group is a name like any other: it can be declared in a module, made public, and used elsewhere
without naming the variables in it.
module heatflow_settings
use, intrinsic :: iso_fortran_env, only: int32, real64
implicit none
private
public :: grid_spec_t, grid, seed, settings, apply_text
type :: grid_spec_t
integer(int32) :: nx = 21, ny = 21
real(real64) :: lx = 1.0_real64, ly = 1.0_real64
end type grid_spec_t
type(grid_spec_t) :: grid
integer(int32) :: seed = 42
namelist /settings/ grid, seed
contains
subroutine apply_text(text, stat)
character(len=*), intent(in) :: text(:)
integer, intent(out) :: stat
read (text, nml=settings, iostat=stat)
print '(a, i0)', 'seed=', seed
end subroutine apply_text
end module heatflow_settings
program namelist_derived
use heatflow_settings, only: grid, settings, apply_text
implicit none
character(len=60) :: text(1)
integer :: stat
! Components are addressed with %, and the whole variable can be given as a list of components.
text(1) = '&settings grid%nx = 41, grid%lx = 2.0, seed = 7 /'
call apply_text(text, stat)
print '(a, i0, a, i0, a, i0, a, f3.1)', 'stat=', stat, ' nx=', grid%nx, ' ny=', grid%ny, ' lx=', grid%lx
text(1) = '&settings grid = 11, 12, 0.5, 0.25 /'
call apply_text(text, stat)
print '(a, i0, a, i0, a, i0, a, f4.2)', 'stat=', stat, ' nx=', grid%nx, ' ny=', grid%ny, ' ly=', grid%ly
! The group is a single name that any program unit with access to it can read or write.
write (*, nml=settings)
end program namelist_derived
GNU Fortran 16.2, then LLVM Flang 23:
seed=7
stat=0 nx=41 ny=21 lx=2.0
seed=7
stat=0 nx=11 ny=12 ly=0.25
&SETTINGS
GRID%NX=11 ,
GRID%NY=12 ,
GRID%LX= 0.50000000000000000 ,
GRID%LY= 0.25000000000000000 ,
SEED=7 ,
/
seed=7
stat=0 nx=41 ny=21 lx=2.0
seed=7
stat=0 nx=11 ny=12 ly=0.25
&SETTINGS GRID= 11 12 .5 .25,SEED= 7/
Source: J3/23-007r1 clauses 8.9 (NAMELIST statement), 13.11.3 (Namelist input) and 13.11.4 (Namelist output)
The output shows that GNU Fortran writes a derived-type group object component by component (GRID%NX=11) while Flang
writes it as one list (GRID= 11 12 .5 .25); both are valid input for the other direction.
A public group with a private object (Fortran 2023)
Before Fortran 2023 a public namelist group could not contain a private variable. Fortran 2023 removes that
restriction ("A PUBLIC namelist group can have a PRIVATE namelist group object", Introduction of J3/23-007r1), which lets a
module expose one name that reads and writes some hidden state. The example below is the shortest way to see whether a
compiler has it: neither GNU Fortran 16.2 nor LLVM Flang 23 accepts it.
module heatflow_settings
use, intrinsic :: iso_fortran_env, only: int32, real64
implicit none
private
public :: grid_spec_t, grid, settings
type :: grid_spec_t
integer(int32) :: nx = 21, ny = 21
real(real64) :: lx = 1.0_real64, ly = 1.0_real64
end type grid_spec_t
type(grid_spec_t) :: grid
integer(int32), private :: secret_seed = 42 ! private variable ...
namelist /settings/ grid, secret_seed ! ... in a public namelist group (Fortran 2023)
end module heatflow_settings
program namelist_private
use heatflow_settings, only: grid, settings
implicit none
write (*, nml=settings)
end program namelist_private
GNU Fortran 16.2:
09b_namelist_private_f2023.f90:5:39:
5 | public :: grid_spec_t, grid, settings
| 1
Error: NAMELIST object 'secret_seed' was declared PRIVATE and cannot be member of PUBLIC namelist 'settings' at (1)
LLVM Flang 23:
error: Semantic errors in 09b_namelist_private_f2023.f90
09b_namelist_private_f2023.f90:14:29: error: A PRIVATE namelist group object 'secret_seed' must not be in a PUBLIC namelist
namelist /settings/ grid, secret_seed ! ... in a public namelist group (Fortran 2023)
^^^^^^^^^^^
Until both compilers accept it, make the variable public or keep the whole group private and expose a subroutine, as
apply_text does in the previous example.
Errors, and how far the compilers agree
A namelist read can fail in several ways, and this is the area where the compilers differ most. The program below feeds one
group seven inputs and reports the status class and the iomsg= text of each.
program namelist_errors
use, intrinsic :: iso_fortran_env, only: int32, real64, iostat_end
implicit none
integer(int32) :: nx = 21
real(real64) :: alpha = 1.0_real64
character(len=60) :: text(1)
character(len=100) :: msg
integer :: stat
namelist /run/ nx, alpha
call try('&run nx = 41 /')
call try('&run ny = 41 /')
call try('&run nx = 4.5 /')
call try('&run alpha = abc /')
call try('&other nx = 1 /')
call try('&run nx = 41')
call try('nx = 41 /')
contains
subroutine try(input)
character(len=*), intent(in) :: input
character(len=11) :: outcome
text(1) = input
msg = ''
nx = 21
alpha = 1.0_real64
read (text, nml=run, iostat=stat, iomsg=msg)
if (stat == 0) then
outcome = 'ok'
else if (stat == iostat_end) then
outcome = 'end of file'
else
outcome = 'error'
end if
print '(6a, i0, a, f3.1)', input, ' -> ', trim(outcome), ' [', trim(msg), '] nx=', nx, ' alpha=', alpha
end subroutine try
end program namelist_errors
GNU Fortran 16.2, then LLVM Flang 23:
&run nx = 41 / -> ok [] nx=41 alpha=1.0
&run ny = 41 / -> error [Cannot match namelist object name ny] nx=21 alpha=1.0
&run nx = 4.5 / -> error [Cannot match namelist object name .5] nx=21 alpha=1.0
&run alpha = abc / -> error [Cannot match namelist object name abc] nx=21 alpha=1.0
&other nx = 1 / -> ok [] nx=21 alpha=1.0
&run nx = 41 -> end of file [End of file] nx=41 alpha=1.0
nx = 41 / -> ok [] nx=21 alpha=1.0
&run nx = 41 / -> ok [] nx=41 alpha=1.0
&run ny = 41 / -> error ['ny' is not an item in NAMELIST group 'run'] nx=21 alpha=1.0
&run nx = 4.5 / -> ok [] nx=4 alpha=1.0
&run alpha = abc / -> error [Bad real input data at column 15 of record 1] nx=21 alpha=1.0
&other nx = 1 / -> end of file [End of file during input] nx=21 alpha=1.0
&run nx = 41 -> error [No '/' found after NAMELIST group 'run'] nx=41 alpha=1.0
nx = 41 / -> end of file [End of file during input] nx=21 alpha=1.0
| Input | GNU Fortran 16.2 | LLVM Flang 23 |
|---|---|---|
|
error, |
error, |
|
error, reported as an unknown name |
accepted: |
|
error, |
error, |
|
no error, nothing read ( |
end of file |
|
|
error, |
|
no error, nothing read |
end of file |
What a program can rely on: a valid input gives status zero on both; a bad item name or bad value gives a non-zero status
and, with iomsg=, a text meant for a person; and the status of an unsuccessful read must not be compared with a particular
number. The rest is processor dependent or lenient, so a configuration reader should check stat /= 0, show msg, and
treat an end of file the same as an error (the group name was missing or the file is empty). The numeric status values
differ (-2 against 1002 for the overrun above), and the text of iomsg= is not standardised. The standard also makes the group objects undefined after an error or an end
of file (12.11.2 and 12.11.3), so the values the program prints after a failed read (nx=21 above) are what the compilers
happened to leave, not something to depend on; the example reset the variables before every read to make them visible.
The standard asks for an error on a real value for an integer (the value "shall be acceptable for the type of the
corresponding effective item", 13.11.3.3), and that group names match, so Flang’s acceptance of 4.5 for an integer, and
the compilers' handling of a group-name mismatch, are the ones to watch if a configuration file is checked strictly.
Overriding settings from the command line
Because a namelist can be read from a string, one name = value assignment from the command line can be turned into a
one-line namelist and parsed by the same code that reads the file, with the same defaults and the same errors:
program cli_overrides
use, intrinsic :: iso_fortran_env, only: int32, real64
implicit none
integer(int32) :: nx = 21, ny = 21, max_steps = 2000
real(real64) :: alpha = 1.0_real64, dt = 5.0e-5_real64
namelist /heatflow/ nx, ny, alpha, dt, max_steps
character(len=:), allocatable :: arg, text
integer :: i, n, stat
character(len=100) :: msg
do i = 1, command_argument_count()
call get_command_argument(i, length=n)
allocate (character(len=n) :: arg)
call get_command_argument(i, arg)
text = '&heatflow ' // arg // ' /' ! a one-assignment namelist record
read (text, nml=heatflow, iostat=stat, iomsg=msg)
if (stat /= 0) then
print '(5a)', 'bad argument "', arg, '": ', trim(msg)
end if
deallocate (arg)
end do
print '(2(a, i0), a, f4.2, a, es8.1, a, i0)', 'nx=', nx, ' ny=', ny, ' alpha=', alpha, ' dt=', dt, ' max_steps=', max_steps
end program cli_overrides
Run with the arguments nx=41 alpha=0.25 bogus=3 max_steps=500, GNU Fortran 16.2 then LLVM Flang 23 print:
bad argument "bogus=3": Cannot match namelist object name bogus
nx=41 ny=21 alpha=0.25 dt= 5.0E-05 max_steps=500
bad argument "bogus=3": 'bogus' is not an item in NAMELIST group 'heatflow'
nx=41 ny=21 alpha=0.25 dt= 5.0E-05 max_steps=500
(Character values need quotes, which the shell removes, so solver='jacobi' has to be quoted twice on a command line.)
Non-advancing I/O
A normal (advancing) data transfer statement reads or writes one or more whole records: after it, the file is positioned
after the record. With advance='no' the statement leaves the file positioned inside the current record, so the next
statement continues where the last one stopped (12.3.4.2). It is the tool for prompts, for building a record from several
statements and for reading a record whose length is not known in advance.
The specifiers
| Specifier | Meaning and rules | Clause |
|---|---|---|
|
nonadvancing transfer; the value is |
12.6.2.4 |
|
a scalar integer variable that receives the number of characters transferred by data edit descriptors, not counting padding blanks. Input only (C1213), never in list-directed or namelist input (C1214); defined when the statement completes, or at the wait for asynchronous input |
12.6.2.16 |
|
branch taken at an end-of-record condition; needs |
12.11.4 |
|
zero on success, positive on error, |
12.11.5 |
|
|
12.5.6.14, 12.6.2.11 |
Annex C.1 of the standard lists "The SIZE= specifier can be used with advancing input" among the features new in Fortran 2018,
so before that a compiler could demand advance='no' with size=; GNU Fortran 16.2 still does:
program constraint_errors
implicit none
character(len=20) :: text
character(len=4) :: item
integer :: got
text = 'abcd'
read (text, '(a4)', advance='no') item ! advance= with an internal file
read (*, *, size=got) item ! size= with list-directed input
read (*, '(a4)', eor=10) item ! eor= without advance='no'
10 continue
end program constraint_errors
17_constraint_errors.f90:8:30:
8 | read (text, '(a4)', advance='no') item ! advance= with an internal file
| 1
Error: ADVANCE tag at (1) is incompatible with internal file
17_constraint_errors.f90:9:20:
9 | read (*, *, size=got) item ! size= with list-directed input
| 1~~
Error: SIZE tag at (1) requires an ADVANCE tag
17_constraint_errors.f90:10:25:
10 | read (*, '(a4)', eor=10) item ! eor= without advance='no'
| 1
Error: EOR tag at (1) requires an ADVANCE tag
LLVM Flang 23 reports the first and third as errors (If ADVANCE appears, UNIT=internal-file must not appear and
If EOR appears, ADVANCE with value 'NO' must also appear) and the second only as a portability warning (If FMT=* appears, SIZE should not appear).
Prompts, and records built item by item
On output, a nonadvancing write leaves the record open. The classic use is a prompt; the other is a record whose items
are produced by a loop, where the separator must go between items and not after the last:
program nonadvancing_output
use, intrinsic :: iso_fortran_env, only: int32, real64
implicit none
real(real64) :: row(5)
integer(int32) :: j, unit
character(len=200) :: line
integer :: stat
! A prompt: the cursor stays on the line because advance='no' leaves the record open.
write (*, '(a)', advance='no') 'Grid size nx: '
write (*, '(a)') '41'
! One CSV row built item by item, with no trailing comma.
row = [5.0_real64, 12.5_real64, 25.0_real64, 12.5_real64, 5.0_real64]
open (newunit=unit, status='scratch', action='readwrite', iostat=stat)
do j = 1, size(row)
if (j > 1) write (unit, '(a)', advance='no') ','
write (unit, '(f0.2)', advance='no') row(j)
end do
write (unit, '(a)') '' ! an advancing write completes the record
rewind (unit)
read (unit, '(a)') line
print '(3a)', '[', trim(line), ']'
close (unit)
end program nonadvancing_output
Both compilers print the same:
Grid size nx: 41
[5.00,12.50,25.00,12.50,5.00]
The loop writes , before every item but the first (the alternative, a format with the colon edit descriptor
in one statement, is what write_csv in heatflow_io uses, with (*(es12.5,:,","))), and the final advancing write (unit, '(a)') ''
completes the record. The same technique writes a row whose items come from different places.
Two things the standard does not promise, both in C.8.2:
-
The prompt may not be displayed. Annex C.8.2 gives the prompt as an example and then says "This document does not require that an implementation of nonadvancing input/output operate in this manner": an implementation can defer the display of a record until it is complete. A
flush (output_unit)after the prompt (theflushstatement, 12.9) asks for it to be shown before the program waits for input. The examples here write to a pipe, so the prompt behaviour on a terminal was not observed. -
What happens to an open record at the end. If a nonadvancing output statement leaves a file positioned within the record and no other output statement follows before the file is closed or a
backspace,endfileorrewindis executed, "the effect is as if the output statement were the corresponding advancing output statement" (12.3.4.2). On the standard output, both compilers leave the last record without a line terminator when the program ends:
program open_record_at_exit
implicit none
write (*, '(a)', advance='no') 'no final newline'
end program open_record_at_exit
The output is no final newline, with no line feed after it, on both GNU Fortran 16.2 and LLVM Flang 23. Finish every
nonadvancing sequence with an advancing statement.
Reading a line of unknown length
An advancing read (unit, '(a)') line into a fixed-length variable cuts a long line and pads a short one, and a
deferred-length variable is not allocated by a read. The portable way to read a whole record of any length is to read it in
chunks with advance='no', using size= to know how many characters each chunk really contains and iostat_eor to know when the
record ended:
module line_reader
use, intrinsic :: iso_fortran_env, only: iostat_end, iostat_eor
implicit none
private
public :: read_line
contains
!> Read one record of any length into a deferred-length string.
!> stat is 0 on success, iostat_end at end of file and positive on error.
subroutine read_line(unit, line, stat)
integer, intent(in) :: unit
character(len=:), allocatable, intent(out) :: line
integer, intent(out) :: stat
character(len=64) :: chunk
integer :: got
line = ''
do
read (unit, '(a)', advance='no', iostat=stat, size=got) chunk
line = line // chunk(1:got) ! got characters were transferred, padding not counted
if (stat == iostat_eor) then ! end of the record: the line is complete
stat = 0
return
end if
if (stat /= 0) return ! end of file or error
end do
end subroutine read_line
end module line_reader
program read_lines
use line_reader, only: read_line
use, intrinsic :: iso_fortran_env, only: iostat_end
implicit none
character(len=:), allocatable :: line
integer :: unit, stat, n
open (newunit=unit, status='scratch', action='readwrite')
write (unit, '(a)') 'short'
write (unit, '(a)') ''
write (unit, '(a)') repeat('x', 150)
write (unit, '(a)') 'last line'
rewind (unit)
n = 0
do
call read_line(unit, line, stat)
if (stat == iostat_end) exit
if (stat /= 0) stop 'read error'
n = n + 1
print '(a, i0, a, i0, 3a)', 'line ', n, ' has ', len(line), ' characters [', line(1:min(len(line), 10)), ']'
end do
close (unit)
end program read_lines
Both compilers print the same:
line 1 has 5 characters [short]
line 2 has 0 characters []
line 3 has 150 characters [xxxxxxxxxx]
line 4 has 9 characters [last line]
How it works: a nonadvancing read of an a edit descriptor of 64 characters takes up to 64 characters of the current record.
If the record has more, the statement completes with status zero and the file stays in the record; if the record has fewer,
the end-of-record condition occurs, iostat is iostat_eor, the chunk is padded with blanks (pad mode yes), and size= has
the number of characters really read, which is what chunk(1:got) appends. The empty second line is a record of zero
characters: got is 0 and the status is iostat_eor at once. End of file is a different, also negative, status
(iostat_end), and the loop in the main program stops on it. The same function can be the basis of a library that reads
text data files line by line, with index or split (F2023) to cut the line afterwards.
The two statuses are tested more readably with the intrinsic functions is_iostat_end and is_iostat_eor
(16.9.116 and 16.9.117), which return true for any value of the processor’s end-of-file and end-of-record status:
program iostat_values
use, intrinsic :: iso_fortran_env, only: iostat_end, iostat_eor
implicit none
integer :: n, stat
character(len=4) :: text
print '(2(a, i0))', 'iostat_end=', iostat_end, ' iostat_eor=', iostat_eor
text = ''
read (text, *, iostat=stat) n
print '(a, i0, a, l1, a, l1)', 'empty record: stat=', stat, ' is_iostat_end=', is_iostat_end(stat), ' is_iostat_eor=', is_iostat_eor(stat)
text = 'x'
read (text, *, iostat=stat) n
print '(a, l1, a, l1, a, l1)', 'bad value: stat>0 ', stat > 0, ' is_iostat_end=', is_iostat_end(stat), ' is_iostat_eor=', is_iostat_eor(stat)
end program iostat_values
Both compilers print the same:
iostat_end=-1 iostat_eor=-2
empty record: stat=-1 is_iostat_end=T is_iostat_eor=F
bad value: stat>0 T is_iostat_end=F is_iostat_eor=F
The eor= specifier and incomplete records
eor=label is the older way to react to the end of a record (it is not obsolescent, see below): control branches to the
label, the item is padded as with iostat=, and the file is positioned after the record. Its drawbacks are the label and
the branch out of the middle of a loop; iostat= with iostat_eor gives the same information without them, so it is the
better default. Both are shown here, on a file whose last record has no line terminator:
program eor_and_incomplete
use, intrinsic :: iso_fortran_env, only: iostat_end, iostat_eor
implicit none
character(len=8) :: chunk
integer :: unit, got, stat
! A file whose last record has no line terminator (written as a stream of bytes).
open (newunit=unit, file='eor_demo.txt', access='stream', form='unformatted', status='replace')
write (unit) 'abc' // achar(10) // 'defgh'
close (unit)
open (newunit=unit, file='eor_demo.txt', status='old', action='read')
! eor= branches when the record is shorter than the item; size= says how many characters arrived.
chunk = '--------'
read (unit, '(a8)', advance='no', eor=100, size=got) chunk
print '(a)', 'no end of record: not reached'
stop
100 continue
print '(a, i0, 3a)', 'eor: got=', got, ' chunk=[', chunk, '] (pad=yes filled the rest with blanks)'
! With iostat= the same condition is reported as iostat_eor, and the record is complete.
chunk = '--------'
read (unit, '(a8)', advance='no', iostat=stat, size=got) chunk
print '(a, l1, a, i0, 3a)', 'stat==iostat_eor: ', stat == iostat_eor, ' got=', got, ' chunk=[', chunk, ']'
print '(a, l1)', 'stat==iostat_end: ', stat == iostat_end
close (unit, status='delete')
end program eor_and_incomplete
Both compilers print the same:
eor: got=3 chunk=[abc ] (pad=yes filled the rest with blanks)
stat==iostat_eor: T got=5 chunk=[defgh ]
stat==iostat_end: F
The last record defgh has no terminator, and both compilers treat it as a complete record (end of record, not end of
file), which is what most programs want. The standard’s distinction between a complete and an incomplete record, which turns
the end-of-record condition into an end-of-file condition, is made for stream files (12.11.1 and 12.3.3.4); these two compilers
did not make it for a formatted sequential file.
Pad mode
The pad mode decides what happens when the input list needs more characters than the record has. With pad='yes'
(the default for a connection) the record is logically extended with blanks, which is why reading '(a8)' from a 3-character
record gives abc and five blanks. With pad='no' an advancing read shall not require more characters than the record contains (12.6.4.5.3), and a
nonadvancing read gets an end-of-record condition. The compatibility clause of the standard (4.3.8) records that Fortran 77
required the number of characters the input list needs to be at most the number in the record, and that the standard now
pads unless pad='no' is in effect.
program pad_no
use, intrinsic :: iso_fortran_env, only: iostat_eor
implicit none
character(len=8) :: item
integer :: unit, stat
character(len=100) :: msg
open (newunit=unit, status='scratch', action='readwrite', pad='no')
write (unit, '(a)') 'abc'
write (unit, '(a)') 'def'
rewind (unit)
item = 'XXXXXXXX'
read (unit, '(a8)', iostat=stat, iomsg=msg) item ! advancing, pad='no': the record is too short
print '(a, l1, a, l1, 3a)', 'advancing: stat>0 ', stat > 0, ' eor ', stat == iostat_eor, ' item=[', item, ']'
print '(3a)', 'iomsg=[', trim(msg), ']'
item = 'XXXXXXXX'
read (unit, '(a8)', advance='no', iostat=stat) item ! non-advancing: end-of-record condition
print '(a, l1, 3a)', 'non-advancing: eor ', stat == iostat_eor, ' item=[', item, ']'
close (unit)
end program pad_no
GNU Fortran 16.2, then LLVM Flang 23:
advancing: stat>0 F eor T item=[XXXXXXXX]
iomsg=[End of record]
non-advancing: eor T item=[XXXXXXXX]
advancing: stat>0 T eor F item=[abcXXXXX]
iomsg=[Excessive input from fixed-size record]
non-advancing: eor T item=[XXXXXXXX]
The advancing read of a short record with pad='no' is a non-conforming program, and the compilers differ again: GNU Fortran
reports an end-of-record condition (negative status, item unchanged), while Flang reports a positive error status and has
already stored the three characters it found (abcXXXXX). The nonadvancing read behaves the same on both.
Error handling for these statements
All the statements on this page report problems through the same conditions (12.11):
| Condition | When | How to handle it |
|---|---|---|
Error |
a bad value, an overrun, an unknown namelist name, a file that cannot be opened |
|
End of file |
input past the last record, or an empty internal file; for namelist also a missing slash (GNU Fortran) |
|
End of record |
nonadvancing input that needs more characters than the record has (and, on GNU Fortran, an internal write that overran) |
|
If a condition occurs in a statement that has no specifier for it (err= or iostat= for an error, end= or iostat= for
end of file, eor= or iostat= for end of record), error termination is initiated (12.11.2, 12.11.3 and 12.11.4); with a
specifier, the program continues and the status is defined. err=, end= and eor= are not in the standard’s list of
obsolescent features (Annex B.3), despite what some textbooks say, but iostat= and iomsg= are the better style because they
work in a do loop without labels and can be passed on. After an error the position of the file is indeterminate (12.11.2), so a
loop should stop, not retry.
Where the books are outdated
The two books consulted for this section describe internal files, list-directed I/O, namelist and nonadvancing I/O as they were in Fortran 90 to 2018. The language has moved on in these places:
| Area | Outdated in the books, current approach |
|---|---|
|
footnotes in one of the books say |
Deferred-length variables |
the books predate Fortran 2023 where a deferred-length allocatable |
Public namelist with private objects |
a public namelist group could not contain a private variable; Fortran 2023 allows it, but no compiler checked here accepts it |
|
described as needing |
Reading an unknown-length line |
the usual advice is a fixed-length buffer and |
Processor-dependent output |
list-directed and namelist output are shown with one compiler’s layout; two compilers can differ in width, digits, leading zeros and record breaks, so output that another program parses needs an explicit format |
Compiler context |
the books do not say which compilers implement which behaviour; the tables on this page show where GNU Fortran 16.2 and LLVM Flang 23 differ (overrun status, namelist errors, real-to-integer input, pad mode) |
Standard version provenance and compiler support
| Feature | Standard | Compiler support checked on 2026-10-19 |
|---|---|---|
Internal files for formatted, list-directed and namelist transfer, |
in the standard before Fortran 2023 (the Introduction of J3/23-007r1 lists only the F2023 changes; the editions that added each are not confirmed here) |
GNU Fortran 16.2 and LLVM Flang 23 |
|
in the standard before Fortran 2023 (16.9.116, 16.9.117, 16.10.2.16, 16.10.2.17) |
both |
|
Fortran 2018 (Annex C.1) |
Flang 23 accepts it; GNU Fortran 16.2 requires |
Deferred-length allocatable scalar as the unit of an internal |
Fortran 2023 (12.4, Introduction) |
not implemented by GNU Fortran 16.2 or LLVM Flang 23 |
Deferred-length allocatable |
Fortran 2023 (12.11.6, Introduction) |
not implemented by either (see Characters and Strings) |
A public namelist group with a private object |
Fortran 2023 (8.9, Introduction) |
rejected by GNU Fortran 16.2 and LLVM Flang 23 |
Different output for real zero in list-directed and namelist output |
compared with Fortran 95 (4.3.6) |
both print a form of zero, in different layouts |
Comments, |
as in 13.11.3 |
both |
Not checked here, because no compiler for them is installed: Intel ifx, NAG, HPE Cray and NVIDIA HPC compilers. See History, Standards and Compilers for the per-compiler support table, and What’s New and Fortran 2028 Preview for the features added by Fortran 2023.
Pitfalls
-
A character constant is not an internal file.
read ('42', *) ndoes not compile; assign the text to a variable. -
Writing more than the record holds. An internal
writethat does not fit is an error whose status is processor dependent (end-of-record on GNU Fortran, a positive error on Flang). Size the buffer, and useiostat=. -
Reading from a record that was never written. An unset
character(len=100) :: lineis undefined; assignline = ''first, or the read sees garbage. -
A short
writeleaves the rest blank.trimorlen_trimthe buffer before using it, or the padding becomes part of the result. -
List-directed input is lenient.
read (text, *) xstops at a blank, comma or slash and accepts'0.25 trailing'; a slash silently ends the whole statement and leaves the remaining items unchanged. -
Null values hide missing data.
5, ,leaves the second item at whatever value it had; initialize items so that "not given" is detectable. -
An undelimited string stops at the first blank. Quote strings that contain blanks, commas or slashes, in input and (with
delim=) in output. -
Never parse
print *output. Its layout is the compiler’s choice. Use an explicit format, ordelim=and namelist for data that a program must read back. -
Namelist objects keep their value when absent. That is a feature (defaults), but it also means a misspelled name that is silently ignored by a lenient compiler leaves the default in force; check
iostat, and print the settings that were used. -
A namelist file must contain
&group. GNU Fortran reads nothing and reports no error for a file with a different group name, Flang reports end of file; a configuration reader should treat both as an error by checking that something was read. -
Do not compare the
iostatnumber. Compare with zero,iostat_endoriostat_eor, or useis_iostat_endandis_iostat_eor; GNU Fortran and Flang return different positive values for the same errors. -
Namelist output with the default
delimis not valid namelist input when it contains strings with blanks or slashes; adddelim='quote'. -
Enumerations cannot be namelist objects. Use their integer kind.
-
Non-advancing output needs an advancing statement to finish. Both compilers leave the last record of the standard output without a line terminator.
-
A prompt is not guaranteed to appear before the
read. Addflush (output_unit). -
size=counts characters of the data edit descriptors, not blanks added by padding; use it, notlen_trim, to find the length of a chunk. -
pad='no'changes errors into conditions. A short advancing record is non-conforming; do not rely on what each compiler does. -
Not every file ends with a newline. Both compilers read a last record with no terminator as a normal record, but check your files and other compilers.
See also Best Practices and Style,
Common Gotchas and Pitfalls,
Error Handling and Program Termination for the
program-level view of iostat=, stop and error stop, and
Testing, Debugging and Profiling for running a build with
the runtime checks that catch an out-of-range internal write.