Fortran 77 Coding Guidelines
Introduction
The following guidelines are designed to encourage consistent coding across
projects and programmers. Many arbitrary low-level decisions are made during
coding. While many of these have no effect on the machine code, they do
affect the appearance of the code. And, consistent practices enhance productivity
and reusability. Project requirements, when applicable, take precedence.
The goals of the guidelines are, in decreasing order of importance:
-
understandability -- conveys the purpose of computations to the reader
-
transportability -- between compilers on assorted modern operating systems
-
maintainability -- can be readily enhanced
-
efficiency -- execution speed
General
Project Organization
-
Use a standardized comment header at the top of every subprogram (see example
in Appendix III).
-
Group related subprograms into a module. The module is assigned a unique
name and is typically stored in one or more files in a single subdirectory
on the file system. If used, a single object library contains the code
for all the module components.
-
The first two letters of the routine and file name correspond to the module
and the remaining four uniquely identify the routine. Additional characters
may be used to create a more sensible name.
Program Units
-
Begin a main program with a PROGRAM statement.
-
Order arguments as follows: inputs, outputs, control, external names.
-
FUNCTIONs must not have side effects.
-
Reference external functions in an EXTERNAL statement.
-
Do not use alternate returns. Every subprogram should have single entry
and exit points.
Statement format
-
Use the standard source format (columns 1-5 for label, 6 for continuation,
and 7-72 for statement).
-
Indicate a non-blank comment with an * in column 1.
-
Indicate a continuation with an & in column 6.
-
Do not split a name across lines.
-
Do not write more than one statement per line.
Statement labels
-
Assign a label only if necessary.
-
Assign labels in ascending order.
-
Assign a separate sequence of labels to FORMAT labels that are groupedat
the end of a subprogram.
-
Right-adjust labels.
-
Do not use the label field of a continuation line.
Capitalization
-
Set keywords in all caps.
-
Set symbolic names of constants (parameters) in all lower case.
-
Set all other identifiers in initial caps with embedded words initial capped.
Spacing
-
Do not use tabs.
-
Write keywords without embedded spaces, but surround keywords with spaces.
-
Do not put space between and array name and its index, Array(I).
-
Put one space between a subprogram name and its argument list, e.g., Subr
(Arg1, Arg2).
-
Except in argument lists, put a space after an open parenthesis and before
a close parenthesis.
-
Put one space between arguments.
-
Use spacing in equations to reveal operators and reinforce precedence.
-
Use indentation to reinforce control flow; each indent is 3 columns.
-
Use whitespace to enhance readability.
Identifier Selection
-
Start with letter [A-Z], follow with only letters or digits.
-
Limit to 31 characters; distinguish with first 6.
-
Choose an identifier to represent the entity being modeled.
-
Explain the significance of each variable and array in comments.
-
Do not use a keyword as an identifier.
-
Do not use a subprogram name as a COMMON block name.
-
Do not abbreviate .TRUE. or .FALSE.
-
Delimit character strings with apostrophes.
Constants
-
Use PARAMETERs to symbolically name all compile-time constants.
-
Use only constant expressions to define PARAMETERs.
Typing
-
Use the following data types:
-
CHARACTER[*n]
-
COMPLEX
-
DOUBLE PRECISION
-
INTEGER*4
-
INTEGER
-
LOGICAL
-
REAL
-
Use DOUBLE PRECISION instead of REAL*8.
-
Use INTEGER for integers that are always in the range of two-byte integers
[-32768,32767]; then use a compiler option to select two or four byte storage.
-
Declare all variables. Use a compiler option or IMPLICIT NONE to ensure
declaration. If no such option is available, setting the implicit type
of all variables to a type that is not used in the program often snags
undeclared variables. An example is:
IMPLICIT LOGICAL (A-Z).
-
Arrange identifiers in type declarations logically based on the entities
which they describe. Subprogram arguments may be declared in order of appearance
in the argument list. If there is no other obvious order, arrange alphabetically.
-
Do not compare arithmetic expressions of different types; type convert
explicitly.
-
Use generic versions of functions, e.g., SQRT instead of DSQRT, unless
the function return value is being passed as passed as an actual argument.
Operators
-
Do not use .EQ. and .NE. between floating point expressions.
-
Use .GE. or .LE., as appropriate, instead of .EQ. when checking for a threshold
crossing.
-
Compare unequal length character strings with LGE, LGT, LLE, and LLT.
-
Use only the logical operators .AND., .OR., .EQV., .NEQV., and .NOT., and
only use them on LOGICAL operands.
-
Avoid .NE. in an IF construct expression that has an ELSE; reverse the
blocks so that the ELSE block handles the logical negation.
Expressions
-
Surround low precedence operators with space.
-
Split an expression across lines after an operator.
-
Indent continuation lines.
-
Consider the types of operands and their effects on the values of subexpressions,
e.g., 8 / 3 * 3.0 is 6.0, not 8.0.
-
Be careful with "exact" values of floating point expressions, e.g., assigning
30.0 / 0.1 to an integer may define it as 299!
Arrays
-
Declare array dimensions in the type declaration rather than in a separate
DIMENSION statement.
-
Use only INTEGER subscript expressions.
-
Preferably operate on arrays such that the first indices vary fastest and
the last vary slowest.
-
Specify all subscripts in any array reference.
-
Do not exceed the bounds of declared array dimensions.
-
Remember, by FORTRAN default, all array subscripts start at 1. To dimension
an array so that it's subscripts start at 0, declare it like this: dimension
a(0:50)
Control structures
-
Use GOTO carefully. See Appendix I for loop constructs. Comments at the
target of a GOTO listing possible 'come froms' are very helpful.
-
Terminate or begin every loop with a distinct CONTINUE or end do.
-
Do not jump into the middle of a loop or conditional.
-
Use STOP only for abnormal termination, and include the reason in thecharacter
string message.
Arguments
-
Match the actual arguments in the caller to the formal arguments of the
callee in both number and type.
-
Do not repeat an actual argument in any call.
-
All arguments to an intrinsic function must be of the same type.
-
Do not pass a constant as an actual argument unless it is to an IN formal
(see Appendix III for definition).
COMMON blocks
-
Place COMMON block definitions in INCLUDE files.
-
Do not mix CHARACTER and non- character types in a COMMON block.
-
Do not pass as an argument any variable referenced in a COMMON block in
both the calling and called subprograms.
-
Initialize COMMON blocks only in BLOCK DATA subprograms.
-
Compile BLOCK DATA subprograms with another program unit in which it is
referred to with an EXTERNAL statement.
-
Use EQUIVALENCE with care, and only to economize on storage; avoid aliasing
and then only if well commented.
Input/Output
-
Use error recovery options END=, ERR=, and IOSTAT=, and handle all such
conditions gracefully.
-
Position a FORMAT statement immediately following its reference.
-
Position FORMAT statements that are used more than once at the end of the
subprogram.
-
Use implied DO rather than DO loops.
-
OPEN all files with STATUS = 'UNKNOWN' unless otherwise is required.
BIBLIOGRAPHY
The contributions of the following individuals are gratefully acknowledged.
Many laudable suggestions were unilaterally discarded solely in the interest
of keeping this guide as brief as possible. A style guide by its very nature
is subjective. The primary intent of this guide is draw attention to some
of the intricacies of coding in the interest of encouraging consistency.
-
Bierman, Keith, personal correspondence, (8911010025.AA06492@chiba.sun.com)
(31 Oct 1989) and (8911160932.AA05443@chiba.sun.com) (16 November 1989).
-
Caffin, R. N., "More on Fortran Coding Conventions," Fortran Forum 3:3
(ACM, December 1984).
-
Calhoun, Myron A., personal correspondence, (8911061456.AA28516@harris.cis.ksu.edu)
(6 November 1989).
-
Cox, Robert W., personal correspondence, (8910311522.AA03009@ilmarin.c3.lanl.gov)
(31 Oct 1989).
-
Horsfall, Dan, personal correspondence, (9008222053.AA28106@dash.udev.cdc.com)
(22 Aug 1990).
-
Liesenfeld, Ulrich, personal correspondence,(1955:uli@analyt.chemie.uni-
bochum.dbp.de) (16 November 1989).
-
Metcalf, Michael, FORTRAN Optimization (New York: Academic Press, Inc.,
1982).
-
Metcalf, Michael, "FORTRAN 77 Coding Conventions," ForTec Forum 2:4 (ACM,
December 1983).
-
Miller, Geoff, "Bureau of Transport Economics Computer Users Guide, Attachment
1 - FORTRAN Programming Standards" (Canberra: Computer Centre, Australian
Defence Force Academy, 8 August 1986).
-
Montgomery, Peter, personal correspondence,(8910311752.AA20351@sonia.math.ucla.edu)
(31 Oct 1989).
-
Spector, Walter, personal correspondence,(9008022256.AA16278@sequoia.cray.com)
(02 Aug 1990).
-
Watson, Ian, personal correspondence, (8912061409.AA05518@Kodak.COM) (6
Dec 1989).
APPENDIX I. Loop Constructs
iterative
DO 10 I = 1, iterations
. . .
10 CONTINUE
OR:
do I = 1, iterations
. . .
end do
Do not modify the loop variable.
while
10 CONTINUE
. . .
IF ( condition ) GOTO 20
. . .
GOTO 10
20 CONTINUE
do-while or repeat-until (all statements in loop execute at least once)
10 CONTINUE
. . .
IF ( condition ) GOTO 10
APPENDIX II. Suggested Compiler Options
-
VAX FORTRAN: /check=(bounds,overflow)/g_float/standard/warnings=all
-
MS fl: /4I2 /4Yd /Ox (/G2 for 80286/386 instructions)
-
Sun f77: (fp is floating point hardware option, e.g., 68881 j is optimization
level)
-
Sun3 f77 version 1.2 and earlier: -ansi -ffp -u -Oj foo.f /usr/lib/fp/libm.il
/usr/lib/libm.il -lm
-
Sun3 f77 version 1.3: -ansi -fast -u -O3 foo.f -lm
-
Sun4 f77 prior to version 1.2: -ansi -u -Oj foo.f /usr/lib/f77/libm.il
-lm
-
Sun4 f77 version 1.2: -ansi -u -Oj foo.f /usr/lib/f77/libm.il /usr/lib/f77/libm.il
-lm (and use -dalign if DOUBLE PRECISION is used; may cause core dump if
code is not all double word aligned)
-
Sun4 f77 version 1.3: -ansi -fast -u -O3 foo.f - lm
-
Convex fc: -ep i -Oj (i is number of processors and j is optimization level)
APPENDIX III. Example
Notes on example:
-
The dividing lines end in column 72, to serve as a visual aid when working
with editors that do not display cursor position.
-
The 'Units' field is useful in physical applications; other parameter properties
may be of interest in other applications.
-
Arguments and common block entities that are referenced in the subprogram
are listed in the prologue. Each may be classified as IN, OUT, or INOUT
mode, following the Ada practice as shown below.
-
A variable is defined if its value is changed, such as by assignment.
-
A variable is used if its value, on entry to the subprogram, is referenced.
mode define use
-----------------------------------------
IN not allowed allowed
OUT allowed not allowed
INOUT allowed allowed
SUBROUTINE TEUpCase (String)
*
* ================== Prologue ==========================================
*
* Purpose:
* Convert a string to all upper case characters.
*
* History:
* Version Programmer Date Description
* ------- ---------- ---- -----------
* 1.0 D. Levine 03/16/89 created
* 1.1 D. Levine 12/11/89 changed to INDEX into
* constant string from adding
* 'A' - 'a' to each char.
*
* IN args/commons Units Description
* --------------- ----- -----------
*
* OUT args/commons Units Description
* ---------------- ----- -----------
*
* INOUT args/commons Units Description
* ------------------ ----- -----------
* String N/A string to be converted
*
* Processing:
* For each character in String, check to see if it is lower case by
* finding its INDEX in the string [a..z]. Then, replace with the
* character at the same position in the string [A..Z].
*
* Special requirements:
* none
*
* ------------------ Include files -------------------------------------
* ------------------ Constant declarations -----------------------------
* ------------------ Argument declarations -----------------------------
CHARACTER*(*) String
* ------------------ Global/External declarations ----------------------
* ------------------ Local declarations --------------------------------
INTEGER Pos, I
CHARACTER*26 lowers, uppers
DATA lowers / 'abcdefghijklmnopqrstuvwxyz' /,
& uppers / 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' /
* ------------------ Code ----------------------------------------------
DO 100 I = 1, LEN (String)
Pos = INDEX (lowers, String(I:I))
IF ( Pos .NE. 0 ) String(I:I) = uppers(Pos:Pos)
100 CONTINUE
RETURN
END
This document was originally written by David L. Levine (levine@ics.uci.edu)
and converted to this hypertext format by Shiva Shenoy.
Back
to the main menu
James Weighton and R.
G. Hindman