### News

USER NOTE
SNS12U
Issue 1
Aug 1996
Common Fortran 77 Problems and
Ways of Avoiding Them

Some errors which occur commonly when writing Fortran 77 programs are described below.

This list is not exhaustive but includes some of the commonest errors, all of which can be avoided either by using appropriate software tools or by employing suitable techniques when writing code.

A number of simple examples are used to illustrate each type of error and the avoidance technique.

Contents

### 1. Incorrect Variable Types

Consider the following program:

c
c Example 1, Incorrect variable types
c
print *, 'Calculate the area of a rectangle'
print *
print *, 'Type the width'
print *, 'Type the length'
area = width * length
print *, 'area = ', area
stop
end

It prompts the user for the width and length of a rectangle and then multiplies them together to give the area. If a width of 2.0 and a length of 3.0 are chosen then the answer of 6.0 is printed as expected. However if a width of 2.0 and a length of 3.5 are chosen, the answer is still 6.0. The reason is the failure to declare the type of the variable length which defaults to integer through the Fortran default typing convention. It is good practice to explicitly declare the type of every variable used in each program unit, even the simple names like i and x.

### 2. Typing Errors in Variable Names

c
c Example 2, Typing errors in variable names
c
real width, length, area
print *, 'Calculate the area of a rectangle'
print *
print *, 'Type the width'
print *, 'Type the length'
area = width * length
print *, 'area = ', arae
stop
end

In the above example care has been taken to explicitly declare each of the variables width, length and area. However each time the program runs it gives the wrong answer regardless of the values given for width and length. The reason is that in the print statement which displays the answer, the variable area has been mis-spelt arae. As far as the compiler is concerned, arae is another program variable which has not been assigned a value. In many cases it will assume the value 0.0 but in general it may take any value.

To avoid such typing errors and to force the explicit declaration of every program variable the statement implicit none is extremely valuable. Inserted at the beginning of each program unit it turns off the default Fortran typing convention, forcing the explicit typing of all variables. With an implicit none in the program unit any typing error will show up immediately as an undeclared variable. Modifying the above example as follows:

c
c Example 2b, Avoiding typing errors in variable names
c
implicit none
real width, length, area
print *, 'Calculate the area of a rectangle'
print *
print *, 'Type the width'
print *, 'Type the length'
area = width * length
print *, 'area = ', arae
stop
end

An attempt to compile the program will give a message of the following form from the compiler:

MAIN:

"ex2b.f", line 13: Error: attempt to use undefined variable "arae"

Note that although implicit none is an extension to the Fortran 77 language it is accepted by almost every compiler.

### 3. Array Bound and Character Subscript Errors

c
c Example 3, Array subscript bound errors
c
implicit none
real a(10)
integer i, j
do 10 i = 1, 10
a(i) = i
10  continue
j = 11
print *, a(j)
stop
end

The array subscript in the print statement of the above program is beyond the declared bounds of the array (1 to 10) and the result is undefined. In many cases the value 0.0 will be printed but in general it could be any value and the program could even fail with a Segmentation Violation error. This type of error is very easily avoided by using the -C compiler option:

% f77 -C ex3.f

Running the program after compiling with the -C option will give a run-time error message of the following form:

Subscript out of range on file ex3.f, line 11, procedure MAIN.
Subscript number 1 has value 11 in array a.
Abort

The -C option will also check that subscripts of character variables lie within bounds.

### 4 . Incorrect Argument Lists in Subroutine Calls

Suppose that example 2 is re-written to perform the calculation in a subroutine as follows:

c
c Example 4, Incorrect subroutine argument lists
c
implicit none
real width, length, area
print *, 'Calculate the area of a rectangle'
print *
print *, 'Type the width'
print *, 'Type the length'
call calcarea( width, length, area )
print *, 'area = ', area
stop
end
c
subroutine calcarea( width, length )
implicit none
real width, length, area
area = width * length
return
end

Compiling and running the program again gives the wrong answer. The reason is that the variable area is missing from the argument list in the subroutine statement so its value is not returned to the main program. Apart from giving the wrong answer as in this case such subroutine argument mismatches can also cause a Segmentation Violation error message. An easy way to check for this sort of error is to use the nag_pfort tool on the Unix service or the High Performance Cluster:

% nag_pfort ex4.f

Processing: ex4.f
NAGWare f77 Tools - Static Semantic Analyser, Version 2.0
[Parsing complete, analysis beginning]
[\$MAIN processed]
[CALCAREA processed]
Error: Wrong number of arguments to CALCAREA in \$MAIN
[Global processing completed]
[nag_analyser Terminated, 1 error detected]
Termination Status ERROR

nag_pfort: *** Stage 1 analysis of ex4.f failed - Stage 2 will not been run ***

Many of the messages output by nag_pfort seem obscure but it has given one clear message indicating the error in the subroutine argument list. It will also check that subroutine arguments agree in type; another common error is to give, say, an integer value for an actual argument where the corresponding dummy argument is real.

### 5. Inconsistent Common Block Declarations

c
c Example 5, Inconsistent common block declarations
c
implicit none
real width, length, area
common /params/ width, length, area
print *, 'Calculate the area of a rectangle'
print *
print *, 'Type the width'
print *, 'Type the length'
call calcarea
print *, 'area = ', area
stop
end
c
subroutine calcarea
implicit none
real width, length, area
common /params/ width, length
area = width * length
return
end

In example 4 the arguments width, length and area could have been passed to and from the subroutine by including them in a common block and declaring that common block in both the main program and the subroutine. However it is just as easy to make mistakes in common declarations especially if they occur many times within a long program.

Fortunately the compilers on the Unix service and the High Performance Cluster will check for this sort of error:

ex5.f:
MAIN:
calcarea:
"ex5.f", line 22: Warning: incompatible lengths for common block params

Such warning messages should be taken seriously because the compiler will still create an executable program and in this case it will give the wrong answer.

A way to avoid inconsistencies in common declarations is to place the common statement and associated type statements in a separate file and include it in each program unit which requires it.

If the file params.include contains the following lines:

real width, length, area
common /params/ width, length, area

the program could be re-written as follows:

c
c Example 5b, Avoiding incorrect common block declarations
c
implicit none
include 'params.include'
print *, 'Calculate the area of a rectangle'
print *
print *, 'Type the width'
print *, 'Type the length'
call calcarea
print *, 'area = ', area
stop
end
c
subroutine calcarea
implicit none
include 'params.include'
area = width * length
return
end

Since the common statement and associated type statements appear in one place only (in the include file) they will be consistent in each program unit which uses that include file.

Note that although the include statement is an extension to the Fortran 77 language it is accepted by almost every compiler.

### 6. Forgetting to Compile New Code

The use of the include statement does not entirely rule out the possibility of a mismatch in common declarations because the program could be in several source files. perhaps one for the main program and one for each subroutine. Changing an include file means that every source file which uses it will have to be recompiled. Failure to recompile one source file will result in that routine still having the old version of the included code.

Unix systems provide a utility called make which can be used to automatically perform all necessary recompilations whenever one or more source files are changed. Type man make for more information. The make utility requires the user to construct a file, normally called makefile, which lists all the dependencies between the program executable, object and source files together with the necessary statements to compile the component parts. The user must construct the makefile correctly in the first place but thereafter, whenever one or more source files are changed, simply typing make will perform all necessary recompilations and create a new executable program file. Take the following example:

Suppose that the file main.f contains the following lines:

implicit none
include 'common.include'
stop
end

and that the file sub.f has the following lines:

implicit none
include 'common.include'
return
end

The include file, common.include, contains the following lines:

A suitable makefile to construct an executable program file called answer would be:

main.o: main.f common.include
f77 -c main.f
sub.o: sub.f common.include
f77 -c sub.f

The makefile indicates that the executable file answer depends on the two object files main.o and sub.o and gives the command for creating the file answer from them. The file main.o in turn depends on the source files main.f and common.include. That dependency is followed by the command to create main.o. Similar information is given for sub.o. Note that the lines beginning f77 are preceded by a TAB character.

When first invoked the makefile performs the following operations:

% make

f77 -c main.f
main.f:
MAIN:

f77 -c sub.f
sub.f:

Both source files are compiled and the resulting object files are linked to give the executable file answer.

If the main program is changed then typing make will do the following:

f77 -c main.f
main.f:
MAIN:

If the subroutine is changed then typing make will do the following:

f77 -c sub.f
sub.f:

If the include file is changed then make will recompile both the main program and the subroutine:

f77 -c main.f
main.f:
MAIN:

f77 -c sub.f
sub.f:

### 7. Formatting Errors in Read Statements

Suppose that the file data has real numbers in fields of width 8 characters, 3 numbers on the first line and 2 on the second:

1.0    2.0    3.0
4.0    5.0

The following program reads the file with a suitable format and prints the numbers on the screen:

implicit none
real array(5)
open( unit=1, file='data' )
print *, array
stop
100 format( 3f8.0 )
end

However, the program gives the following unexpected result:

1.02000 3.00000E-02 0. 4.05000 0.

The reason is that the data file does not have 8 character wide fields; in fact they are only 7 characters wide but this mistake is very hard to spot. Formatted reads are very error prone and in many cases they are unnecessary. In this case it would have been far better to have used a free-format read and the user would not have had to worry about the format of the data file. The only requirement with free-format reads is that the data appear in the correct order in the data file, separated by one or more spaces, commas or new lines. A free-format read in the above example avoids the problem:

implicit none
real array(5)
open( unit=1, file='data' )
print *, array
stop
end