Question

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)

Was it helpful?

Solution

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 REALs, using the other name they are INTEGERs -- 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*8s 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top