Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29274 Discussões

Initialization of a Fortran common block

John6
Principiante
1.878 Visualizações
I am dealing with some legacy fortran 77 programs which utilize the following technique to initialize an entire common block:

At the start of the com include file a block is initialized as follows:
common /someblockname/ aaduma(1)
Then later in the common file, some other variables are initialized in differing places:
common /someblockname/ foo1, foo2, foo3
Then at the very end of the common file, a last block statament is set:
common /someblockname/ zadumi

Later in a program subroutine, the time will come for the variables in the "someblockname" to be initialized (usually to zero).

So the program does the following:

initl=locfun(zadumi)-locfun(aadumi(1))

where locfun is the following (I've included a comment which may or may not be correct):
function locfun(name)
!By treating the variable 'name' as a word composed by four (4) bytes,
!the 'locfun' function returns a location count for the word 'name'
n= loc(name)
locfun= (n+3)/4
return
end


Then the program does the following:
do20 i=1,initl
20 aadumi(i)=0.

So the end result of these operations is that everything in the specific common block named "someblockname" is set to zero. Everything not in "someblockname" is untouched.

My question is: The above Do...20 construct (if the array bounds checking is on) will cause a run-time error when i = 2. If the array bounds checking is off, the program works perfectly (meaning every variablein the "someblockname" block is now correctly set to zero)

Is there a better way to initialize the common block "someblockname" which would allow the array bounds checker to be turned on?

0 Kudos
4 Respostas
John_Campbell
Novo colaborador II
1.878 Visualizações
The code approach you identify does not conform to the standard. I'm not sure when named common declared of different lengths was conforming, but was commonly used.
The use of the LOC approach is an interesting way of generalising the approach, but depends on the actual size of the declared common in the routine where this approach is being used. It appears that someone wanted to let the program count the bytes, as the common block list was being developed. Also, there might be a reason that only this length is initialised and not the full length of /someblockname/ allocated at link time, so you should check that.

My approach would be to use FIND to find all occurrences of this common and identify the longest then declare this length in the routine where it is being zeroed. Say if the longest is 40 bytes, then declare for this routine:

common /someblockname/ aadumi
integer*4 aadumi(10) ! largest known use of /someblockname/
...
aadumi = 0

You can get the length from a load map and most linkers will report inconsistent use of named common lengths, which is annoying for old F77 codes.

In the past my approach had been to declare named common in an include file, and also include a single integer array of the full common length, which is equivalenced to the first element of the common list. Setting this array to zero initialised all elements of the common list.
Now with modern editors, it is relatively easy to copy the list of elements and initialise in a conforming way.
Having all declared common in include files is a preferable approach while using the same common for different temporary variables should be left back with F77.

John
IanH
Colaborador honorário III
1.878 Visualizações
The common block here isn't necessarily of variable length - within a program unit (in this case it appears within the include file that is pulled in by a program unit) you can split the common block definition across multiple statements - the final list of objects for a particularly named common block is the concatenation in source order of the object lists across all the relevant common statements.

(You are correct though, that whatever that size ends up being, in all program units that access that named common block it needs to end up the same size.)

But using LOC is definitely non-standard!

I'd suggest creating a BLOCK DATA program unit that access the common block (via the include file) and then has some DATA statements that explicitly initialise each member of the common block to zero. The aadumi and zadumi sentinels are then no longer required, but you wil then have to manually make sure that the all entities that are declared as being in the common block are initialised in the BLOCK DATA unit. This is a bit error prone, but if you are still using common blocks today then you are just begging for that sort of punishment. This will solve the immediate problem.

Later, you can move the common block definition into a module (the module has the common statements), and rather than using include, use a USE statement to reference that module (simple search and replace, most likely then with repositioning of the USE statement).

Then later still, you can get rid of the common blocks (and the include file) and make the variables module variables. At the same time you get rid of the BLOCK DATA program unit (or the relevant part of that unit - it might be initialising other common blocks) and move the initialisation to each module variables' declaration.

Then you can sleep easy at night, knowing that your code is no longer using some arcane hack from a bygone era.

(Edits to fix me bad grammar, and to note that when the OP makes these changes he can get rid of the integer*4 business too.)
John_Campbell
Novo colaborador II
1.878 Visualizações
John needs to be careful resorting to BLOCK DATA or initialisation in the MODULE as the DO loop controls when the zeroing takes place, which may not be at the start of the run.
There is also some reduced capability in the use of MODULE, for the coding technique identified, as MODULE does not provide the same variable sequence order, that was assumed when utilising past COMMON structures.
As for the use of INTEGER*4, this arcane hack will always use this syntax, as I'm sure that John has found, itclearly and concisely documents the precision required in an old code which may have lost some of it's development history. Understanding the byte size of a variable was important when I was a novice hack.
While Selected_.._Kind provides the allusion of a large range of possible precisions, the reality is there are only3 or4 available and only 2 required for REAL. Wouldn't it be good to dial up what ever PRECISION you wanted!
John6
Principiante
1.878 Visualizações
The result of the operation is that all variables within /someblockname/ are initialized.
I believe this is the full block (the block someblockname) length.
Also, you are quite correct in that this is not done at the beginning of the program.
It is done at an initialization point in the program.
The /someblockname/ is in an include file com.fi with other named common blocks which are not re-initialized.
The point of doing this involved repeated running of the program.
The variables in the /someblockname/ are initialized to zero and the variables in /anotherblockname/ are not. The initialization (clearing) is done so that on the subsequent runs through the program, variables in /someblockname/ which were read or calculated onprevious runs were not left over for thenext run through the guts of the program. They were cleared. In the other named commons in com.fi, it didn't matter (the variables get re-calculated) so they weren't cleared.
Responder