Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28434 Discussions

EQUIVALENCE between a COMMON BLOCK and a user defined/type structure

Ibrahim_K_
New Contributor I
669 Views

Friends;

 

I have an old FORTRAN code with a dozen COMMON blocks. I am trying to reform it to modern Fortran and some parts to C++. I want to do this incrementally. The way I was thinking of achieving this by using user defined structures in the new code (probably in a special MODULE) and use EQUIVALENCE to map the same data to the old COMMON BLOCKs in the older part of the code.

Firstly, is it legal in Fortran (I have not tried it yet). Secondly, is there a better way to accomplish what I am trying to do?

Thanks for any help.

I. Konuk

0 Kudos
7 Replies
IanH
Honored Contributor II
669 Views

I would approach this without using equivalence.  First, without changing any legacy code, put the common block and associated type declarations into a module, i.e. given a legacy procedure:

SUBROUTINE legacy
  IMPLICIT NONE
  COMMON /mycommon/a,b,c
  INTEGER :: a
  REAL :: b(2)
  LOGICAL :: c
  
  PRINT *, a, b, c
END SUBROUTINE legacy

create a module such as:

MODULE common_wrapper
  IMPLICIT NONE
  COMMON /mycommon/a,b,c
  INTEGER :: a
  REAL :: b(2)
  LOGICAL :: c
END MODULE common_wrapper

New code then uses this module, without needing to know that the variables provided by the module are in a common block.  This new code continues to interoperate with legacy code, due to the way that storage association works.

If you want to have the variables in an object of derived type, you can use a sequence type.  Again, this is without changing any legacy code.

MODULE common_wrapper2
  IMPLICIT NONE
  TYPE :: t
    SEQUENCE
    INTEGER :: a
    REAL :: b(2)
    LOGICAL :: c
  END TYPE t
  COMMON /mycommon/x
  TYPE(t) :: x
END MODULE common_wrapper2

New code using this module would work with the components of the `x` object, again agnostic to the common block storage of those components, but continuing to interoperate with legacy code that directly uses the common block.

Perhaps that's where your conversion stops, or perhaps you then start to progressively rework the legacy code to use the module instead of directly referencing the common block.  Note that because common blocks work on storage association, names for the same bit of storage can be different for different declarations of the same common block (and worse, the same name in different scopes can refer to different bits of storage of the same common block) - be very careful of such cases when changing legacy code.

Once all references to the common block have been migrated to be via the module, then the common block can be deleted from the module, any variable initialisations from block data can be changed to be module variable initialisations, and away you go, no more storage association.

0 Kudos
Steve_Lionel
Honored Contributor III
669 Views

What you propose is (mostly) legal in Fortran. If the old code refers to the variables a certain way, you can leave it and not add EQUIVALENCE as long as you make sure that the derived types you use occupy the same storage. I can't offhand think of a better alternative.

0 Kudos
Ibrahim_K_
New Contributor I
669 Views

Ian and Steve:

Thank you very much for great ideas and quick response. I think I am going to start with Ian's first solution which is simple enough for me to follow. I may later try the variation he is suggesting because it would be then easy to pass the derived type to C++.

I learn so much at this place (Intel Fortran forum). Thanks very much again. I am also extremely happy that Intel is supporting and updating the Fortran compiler. What would I do if they did not!

From Steve's comment and looking at the reference documents, it seems like as long as one does not mess around splitting and slicing the COMMON BLOCK, it is OK to use EQUIVALENCE. Anyway, I am not going to follow that path.

Regards;

I. Konuk

0 Kudos
FortranFan
Honored Contributor II
669 Views

@I. Konuk,

You may find online resources online such as Fortran Wiki as well as those in Steve's Dr Fortran blog on "modern Fortran" (almost all of them have sections on modernizing legacy code) useful in case you have not reviewed them already:

http://fortranwiki.org/fortran/show/Modernizing+Old+Fortran

https://software.intel.com/en-us/blogs/2013/12/30/doctor-fortran-in-its-a-modern-fortran-world

It will be useful for readers if you can explain how EQUIVALENCE is used in the legacy code of interest to you.  Note the section at Fortran Wiki which states with EQUIVALENCE, "in old code it often turns out to be used in ways which are non-standard, for example to associate numerical variables with ones of character type," i.e., effectively a UNION type of a data structure.  If that's the case, please see this thread: https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/816710 and know the code may need to either continue using the non-standard compiler-based extensions or require considerable refactoring to work with the type (and kind and rank) requirements of standard Fortran 

0 Kudos
Ibrahim_K_
New Contributor I
669 Views

I have implemented Ian's suggestion with a small FORTRAN function which shares a COMMON BLOCK with legacy FORTRAN and a C++ class. All seems to work (I can pass contents including CHARACTER varibales back and forth), but I encountered a strange (perhaps small) problem.

This is my MODULE containing my COMMON BLOCK

MODULE mycommons
    COMMON/KEYS/PROB(4),RUNTYP(4),TITLE(80),KEY(15),KOPT(125,10)
    BIND(C,NAME='KEYS') :: /KEYS/
    CHARACTER :: PROB,RUNTYP,TITLE 
END MODULE mycommons

When I change the CHARACTER declaration to CHARACTER(C_CHAR) or CHARACTER(KIND=C_CHAR) 

as in

MODULE mycommons
    COMMON/KEYS/PROB(4),RUNTYP(4),TITLE(80),KEY(15),KOPT(125,10)
    BIND(C,NAME='KEYS') :: /KEYS/
    CHARACTER(C_CHAR) :: PROB,RUNTYP,TITLE 
END MODULE mycommons

I get

error #6756: A COMMON block data object must not be an automatic object.   [TITLE]

This declaration works if I put the code within the FORTRAN function code instead of MODULE.

Any ideas why? Is it safe to use CHARACTER without C_KIND qualifier within a mixed C++/FORTRAN program?

Regards;

I. Konuk

 

0 Kudos
Steve_Lionel
Honored Contributor III
669 Views

You forgot to USE ISO_C_BINDING, which makes C_CHAR an implicitly declared variable. That turns the declaration of TITLE into an object with a run-time length (automatic) which is not allowed here.

0 Kudos
Ibrahim_K_
New Contributor I
669 Views

Steve:

Thank you so much!

Kindest regards;

I. Konuk

0 Kudos
Reply