common in a module

common in a module

We have a lot of old code that contains common blocks. We have been gradually converting them to modules as it is convenient to do (and test). We have a situation where it would be very helpful - as a temporary measure - to be able to have place a common block in a module but still refer to the common variables outside of the module (blank common, in this case). It seems to work, but, since it is kind of weird thing to do, I thought I'd ask if anyone knew of any potential issues that I might not have run into yet.

13 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

I think that using COMMON in this way may be a bad idea. Try the following example, and note the perplexing results.

module bmod
implicit none
integer p(5)
common p
end module

program xyz
use bmod
implicit none
integer q(5),i,j
common q

do i=1,5
   p(i) = 2*i-3
   q(i) = 2*i+3
end do

write(*,10)(i,p(i),q(i),i=1,5)
10 format(' i   p(i)   q(i)',//,(3i5))
end

 

Personally, I think that blank common are source of problems.

When I had to convert common to modules, I used the following principle.

For each common block, I have created a module  containing a structure (type) thats contains all the variables of the common block and a variable of this type.

In this way, you are guaranteed against conflicts between local variable names and common/modules variables names.

Then everywhere,you ,need to replace common variables by members of the type.

common /com1/v1,v2,...
v1=10
V2=v1*10
...

Replaced by

module common_1
    type (com_1)
          ... v1
          ... v2
          ...
    end type
    type com_1 c1
end module


use common_1

c1.v1=10
c1.v2=c1.v1*10
...

Thank you for your help. I do not have concerns of those particular natures, however. This is a well-ordered commercial application, it's just that some of the code is 40 years old. No programs use multiple definitions of blank common, and in most cases it is used locally as a scratch pad or communication with subroutines used exclusively together. However, we have one case where it is an include file used in 75 different files. We recently tracked down a bug due to a character length in that include file that should have been using a well-established parameter but was actually hard-coded. I'd like to convert this to a module, but there are two other uses (in more than two files) that seem to be constructed to match this one. I simply don't have time to find out if those references depend on using the blank common to communicate with one of the aforementioned 75 files right now (it will be more work than I would like just to modify that many files). I will after the next release cycle. So can I just put the blank common in the module for now, is what I'm wondering about.

I have made extensive use of the ability to have a Module contain (a) common block(s). IMO it is an extremely useful feature of the language, and not something to be avoided because of potential problems.

The program I work on was originally FORTRAN-77, and used Common blocks everywhere. I have now converted almost all of them into modules. The work was reasonably straightforward because I was able to make all changes incrimentally, maintaining a working, tested code throughout.

For each common block, you create a new module, and INCLUDE the block in the module. (Your common blocks are OF COURSE encapsulated into include files, I assume ... otherwise you are in a world of grief before you start!). Then for each routine that uses the block: substitute the USE statement, compile, and test. When you have converted all the routines, you can go back to the module and remove the COMMON statement, leaving the variables as vanilla module variables.

At any stage in this process you can use the ONLY clause on the USE statements, to limit the visibility of variables in each routine.

Now, I admit I never had to deal with blank common, so there may be unforseen problems there. But I doubt they can be as bad as the problems common is allready giving you. Another issue is the dreaded EQUIVALENCE statement. For this you have to decide which side of the fence to be on. You can either keep the COMMON statement in the module, thus allowing the EQUIVALENCE to remain there as well. Or, you can bite the bullet and do the work to convert the code to remove the equivalence. You can play tricks with pointers to get some similar effects to equivalence, but IMO that is little better, and arguably a lot worse, so either do it properly of leave it alone.

I would look at the load map to see how the linker managed the module and the common addresses.

Personally, I would never use common in a module. I am now trying to replace common by a module and trying to remove reliance on the equivalence structure that common provided.

As for common, I always try to place common definitions in an include file (just like how a module works), which is not what blank common is being used for in your example.

If the blank common is being used for a memory pool, I would check to see if this is still required. In the past that was used to place local variables in common, to minimise memory usage, before dynamic allocation of local variables became standard.
If blank common was used as a quick way to transfer information between related routines, which would later not be required, it may be more robust to identify these variables and move them to defined module, common or routine argument lists. These days the memory restrictions are more relaxed and so saving 1k of memory is not really an issue.

I also find that ALLOCATABLE arrays are another innovation that is useful in this type of coding. Combined with being declared in a module, this provides a lot of flexibility for sizing that can simplify the past coding approaches with common.

It all depends on how much you know of the structure of the program before you contemplate changes, as blank common should still work as intended with F77. ( Just be careful about the byte lengths of the variables as they might have changes, especially character storage. )

John

Qolin has a good methodology. A fly in the ointment of named block commons are when different source files use different name mappings. Converting this to module is problematic. An example is

common /someBlockName/ Foo,...

used in one source and

common /someBlockName/ Bar,...

used in a different source .AND. are passing data between them.

BTW, the above confluence is equivalent to an EQUIVALENT equivalence.

Jim Dempsey

 

If your common blocks are well defined with variables types and dimensions in an unique include file, including them in a module is a good solution but I don't see at this point the fundamental difference with "common block" way. For me, common blocks and module variables are not very different and the main problems are the potential conflicts between common block or module variables and local variables. The solution that I proposed is intended to avoid this kind of problem and to ease the modification (adding, renaming  variables).

Quote:

gvautier wrote:
...common blocks and module variables are not very different.

Here is one major difference: module variables are accessed by name. The order of declaration of module variable has no effect (apart from the language rules that govern declarations). Common block variables are accessed by offset from the base of the block. The names do not appear in the executable (unless debugging has been enabled). The same location in a block can be referred to by different names in different subprograms that contain the block. Even the type can differ (it is probably a bad idea to use this inauspicious feature).

In a large project (100's to 1000's to 10000's of source files), it is not unusual for many of the source file being borrowed from other project, other users, and whatnot. These programs, if they are F77 or older may have used COMMON blocks to pass arguments and to hold states.

In such circumstances, it is highly unlikely that the different developers, over decades of time, would have chosen the same names to use on their variables. In these circumstances,

First produce a list of all COMMON blocks and sort by name of block. This is awkward when common blocks are multi-line. You also must include the variable type and declarations. Where PRAGMA's are used, or #define are used, you also need the values as used by the source referencing the common.

Only when all the attributes match (name, type, dimension) can you then "simply" port the declaration into a module - somewhat as-is with the COMMON line commented out. I generally choose a module name with "mod_" prepended to the former common block name. This helps in correlating between older working program and newer broken program during conversion.

When they differ, then either you have exposed a latent bug or a required alternate naming feature or something benign. In this situation, it is difficult, as you need to determine as to if latent bug or required alternate naming feature. A benign use would be where the addresses mapped for variable storage are purely temporary and not used to pass data or hold data between calls. Make the temps stack local (unless overly large) otherwise consider SAVE for the temps.

For alternate naming, consider using the ASSOCIATE localVarName => moduleOtherNameVar

Be aware that this is not always easy when a same named variable is used but in different positions in their respective common blocks. This has to be done carefully.

Jim Dempsey

 

Quote:

mecej4 wrote:

 

Here is one major difference: module variables are accessed by name. The order of declaration of module variable has no effect (apart from the language rules that govern declarations). Common block variables are accessed by offset from the base of the block. The names do not appear in the executable (unless debugging has been enabled). The same location in a block can be referred to by different names in different subprograms that contain the block. Even the type can differ (it is probably a bad idea to use this inauspicious feature).

I agree that common blocks are different from module variables. But even in F77, using common blocks with varying declarations was source of problems that can be very difficult to solve even by the original programmer. It was useful in some circumstances but very dangerous. For me, the only safe way to use common blocks was to have an unique declaration in an include file and in that way, the difference with module variables is very limited.

 

 

 

Don't forget that before dynamic allocation of local variables was available, blank common was often used to store local variables to reduce memory usage. If you have blank common with local definitions that are different, this may be the case. Although less likely, it still could occur if the common definition was "included", as this would be limited to grouped parts of the code. It's not a robust form of coding, but it did happen, especially when overlays were required.

John

Thank you all for your help.

 

Leave a Comment

Please sign in to add a comment. Not a member? Join today