Doctor Fortran in "Revert! Revert! The End (of the format) is Nigh!"

Recently, a customer wrote in our User Forums that he wanted to write out the values of an array, all in one line, where the number of elements was not known at compile time.  His first attempt at this was:

write (30,'(2x,f8.2)') array

and he was dismayed to find each element written on a new line.  He had then tried this variant:

write (30,'(2x,f8.2)',advance='no') array

reasoning that the "advance='no'" would prevent the new lines.  No good - still one element per line.

Another user suggested this:

write (30,'(2x,(f8.2))') array

but this was worse in that the first line had two spaces before the number but subsequent lines did not.

What's happening here?  What is the best way to write a format that will give a specific format to a variable number of values?

Bouncing off a hard, rubber wall

The odd behavior is due to a little-understood Fortran language feature called "format reversion".  This dates back to at least Fortran 77, if not Fortran IV, and specifies what happens when you get to the end of the format but still have items to process.  A new record is started, (technically, it behaves as if a '/' edit descriptor was processed), and "format control then reverts back to the beginning of the format item terminated by the last preceding right parenthesis... If there is no such preceding right parenthesis, format control reverts to the first left parenthesis of the format specification."

If we take the original format above,


and assume that the array has three elements, this ends up being equivalent to:


because there is no preceding right parenthesis, so control reverts back to the beginning of the format and three records will be created.  Even if advance='no' is added, we'll get three records because "non-advancing I/O" is about what happens at the end of the I/O statement, not the middle of it.

Now let's look at the proposed fix:


This ends up being equivalent to:


as the end of the (f8.2) group is the preceding right parenthesis, so we revert to the beginning of that group. By the way, if there is a repeat count on that group, then the repeat count gets reused.

What to do, what to do

In Fortran 2003, there's no really good way of generally attacking this problem.  If you have an idea of an upper limit for the number of elements, you could specify a large repeat count on the group, such as:


This assumes there won't be more than 1000 elements, but is somewhat ugly.  And no, you can't put a PARAMETER constant in for the 1000.  Some people will suggest that you construct a format at run-time by writing into a character variable and using a run-time format, like so:

character(80) :: fmt
write (fmt,'(A,I0,A)') '(',n,'(2x,f8.2))'
write (30,fmt) array

where "n" is the number of elements in the array.

Another option is to use an extension called Variable Format Expressions (VFEs).  This was created by DEC in the 1970s and it earned the enmity of Fortran compiler writers everywhere who were pestered by their customers to support it as well.  With VFEs, you can enclose an integer expression in angle brackets and the value of the expression will be used in the format.  For example:

write (30, '(<n>(2x,f8.2)') array

Intel Fortran, of course, given its DEC heritage, supports VFEs, but I don't recommend their use if you have other reasonable options.

Look to the future

Fortran 2008 solves this problem with a feature called the "unlimited format item" where a * can be used as a group repeat count.  Its effect is "as if its enclosed list were preceded by a very large repeat count".  For example:


This lets you avoid having to write a specific large number as the repeat count and makes it more obvious what is going on.  Intel Fortran does not support this yet. [Edit - Intel Fortran added support for the unlimited format item in Intel [Visual] Fortran Composer XE 2011 (compiler version 12.0).]

The Doctor's advice, should you find yourself in this situation, is to use the large repeat count, at least until the compiler you use supports the unlimited format item.  You may find some cases where VFEs simplify your coding, so feel free to use them if there is no reasonable standard-conforming alternative.

Got suggestions for future Doctor Fortran columns?  Let me know!

For more complete information about compiler optimizations, see our Optimization Notice.


anonymous's picture

Recursive programming in Fortran II by James A. Ayers (General Motors Research Lab, Warren, MI at that time, 1963)

A little while ago I found this article about FORTRAN II (I used FORTRAN II in my first job out of school at
Argonne National Lab)
and want to read it, but don't want to pay the big bucks to ACM (especially since it is 49 years old.)
I thought you might have a copy lying around or have sufficient privileges to get a free copy.

joseph-krahn's picture

You can use a CHARACTER parameter, for example:

character(len=*), parameter :: fmt_huge='99999'
write (30, '('//fmt_huge//'(2x,f8.2))' ) array

Depending on the compiler, you still may run into a fixed output-record length limit for large arrays, unless using the new STREAM I/O.


Steve Lionel (Intel)'s picture


In the earliest days of DEC Fortran 90, years prior to our move to Intel, the compiler indeed had a restriction that VFEs could be in FORMAT statements only. That was resolved and by the time Intel Visual Fortran came out, the restriction was long gone. You may have encountered a bug, though. I am not aware of any issues like that in recent Intel compilers.

You are correct that VFEs are not standard Fortran.


anonymous's picture

I remember having the same problem in the past. I figured it out using
the VFEs. I don't remember where I read about them,
probably at the Fortran Reference Guide shipped with the Intel compilers, because
de ISO Fortran doesn't mention anything about them. However, what I
remember is that the compiler complained about using VFEs in the WRITE
statement, I was only allowed me to use them in an explicit FORMAT declaration.
Did I something wrong, or something has changed since then?


Add a Comment

Have a technical question? Visit our forums. Have site or software product issues? Contact support.