Fortran newbie here, I've been asked to work on an old Fortran codebase written in Fortran 77 with Salford/Silverfrost compiler (the original developer passed away).
The original developer uses named COMMON
blocks extensively (to emulate global variables, AFAIU) and he uses EQUIVALENCE
to (re-)initialize the blocks when needed like in this code snippet:
IMPLICIT REAL*8 (A-H,O-Z)
COMMON/COMMF2D/
* ASCN(0:99,0:20,0:4)
*,FEMPTY2(8700)
DIMENSION KLCKF2D(38400)
EQUIVALENCE (KLCKF2D,ASCN)
DO I= 1,38400
KLCKF2D(I)= 0
END DO
Is this an acceptable programming practice or just a hack? Also, since I'm trying to port the code to GFortran, is it portable? (I understand that declarations like REAL*8
are just hints to the compiler and not guaranteed)
EQUIVALENCE
doesn't do anything, it certainly doesn't intialise anything, an EQUIVALENCE
is a definition or declaration. These days (and ever since the publication of the Fortran 90 standard with a force growing all the time) EQUIVALENCE
is a hack, and should be avoided wherever possible.
The statement declares that 2 variables share storage (what the Fortran standards call storage-association). One interpretation of this is that the names which are equivalenced are simply aliases, but the (ab-)use of the statement allows the programmer to do some other things which are regarded, by 21st century professional software engineers, as well-dodgy.
For example, and this applies in the snippet you've posted, EQUIVALENCE
can be used to have variables of different types share the same storage. You have an array called ASCN
which is (implicitly) of type REAL*8
equivalenced to an array called KLCKF2D
which is (again implicitly) of type INTEGER
. What this means is that if you refer to the storage under one name the bit-patterns are interpreted as REAL
s, using the other name they are INTEGER
s -- and note that the bit pattern for a real with the value 100.0
will not (of course) be interpreted as the integer 100
.
And the hackery doesn't stop there. One effect of the COMMON
block declaration is to lay the variables out in memory, in your case the 10500 (= 100*21*5)
elements of ASCN
are followed by the 8700
elements of FEMPTY2
. With a little multiplication and addition you find that 38400 = 2*(10500+8700)
which accords with the default integer size in this program being 4-bytes, ie half the size of the REAL*8
s used in the other variables. So the array KLCKF2D
is larger than ASCN
but the original programmer knew that the next 17400
bytes would be occupied by FEMPTY2
.
So yes, this may be a way of setting all the bits in that part of your program's in-memory data to 0
, but it's (now considered to be) a horrid hack. But it should be portable -- successive Fortran standards have been very conservative about deleting obsolete features from the language and compiler-writers even more so, backward-compatibility is VERY important to Fortran programmers.
Oh, and to answer your question, yes COMMON
blocks were (note the past tense) the FORTRAN77 way of declaring and using global variables. These days the language offers the much safer option of declaring variables to be shared globally by wrapping them in a MODULE
and USE
-associating them.
I wouldn't have been surprised to see a line like
COMMON/COMMF2D/KLCKF2D(38400)
in your code, COMMON
blocks can also be (ab-)used to rename and retype storage locations.
While I'm giving your old code a kicking, implicit typing is also frowned upon these days, far better to explicitly type all declarations.