Rules For Declaring Structures and Common Blocks

This page contains some rules for declaring fortran common blocks and for declaring structures, in any language. The rules are important for work in a mixed-language and multi-platform environment. They are obeyed inside MCFAST ( well, we think that we have found and fixed all of the violations ... ) and users are encouraged to follow these rules in their own code.

First, one must define an 8 byte boundary: this is as an address which is divisible by 8 without remainder. In a real*8 array, the first element occupies bytes 0 to 7, the second bytes 8 to 15, and so on. Similarly one can define a 4 byte boundary.

The rules are:

  1. In any common block or structure, all 8 byte variables must start at an 8 byte boundary, relative to the start of the common block or structure.
  2. Similarly all 4 byte variables must start at a 4-byte boundary relative to the start of the structure or common.
  3. If a structure contains any 4 byte variables, its total length must be divisible by 4 without remainder.
  4. If a structure contains any 8 byte variables, its total length must be divisible by 8 without remainder.
Rules 3 and 4 are present to ensure that all elments in arrays of structures will statisfy rules 1 and 2.

If structures are nested inside strucutres or common blocks, then the rules reply recursively into the most deeply nested structure.

The reasoning behind these rules is explained at the bottom of this document.

Now for some examples. Consider the variables:


      character*1  c
      character*36 string1
      character*40 string2
      integer*2   i
      integer     j
      real        a
      real*8      b

Bad:  common /test/ i, j   - Fails rule 1

      structure /test/     - Fails rules 1 and 3
         integer*2 i
         integer   j
      end structure

      structure /test/     - Fails rule 3
         integer   j
         integer*2 i
      end structure

      common /test/ c, b        - Fails rule 2
      common /test/ string1, b  - Fails rule 2
      common /test/ i, b        - Fails rule 2
      common /test/ j, b        - Fails rule 2
      common /test/ a, b        - Fails rule 2

      structure /test/          - Fails rules 2 and 4
         integer j
         real*8 b
      end structure

      structure /test/          - Fails rule 4
         real*8 b
         integer j
      end structure

      structure /test/          - Fails rule 2.
         integer j
         real*8  b
         real    a
      end structure

      structure /test/          - Fails rule 4
         real*8 b
         character*36 string1
      end structure

Good:
      integer i
      real*8  a
      common /test/ a, i

      structure /test/
          integer i
	  integer pad
          real*8  a
      endstructure

      structure /test/
          real*8  a
          integer i
	  integer pad
      endstructure

      structure /test/
          real*8  a
          real    b
	  real    pad
      endstructure

      structure /test/
         real*8 b
         character*40 string1
      end structure

Why We Need the Rules

  1. Some machines require, and other only prefer, that:
    • All doubles (real*8) start at an address which is divisible by 8 without remainder.
    • All 4 byte variables start at an address which is divisible by 4 without remainder.
  2. Most machines only start common blocks, single structures and arrays of structures at 8 byte boundaries.
Some machines will not compile things which fail these rules. Other machines will compile and run, but will execute slowly - these machines may or may not print compile-time or run-time warning messages. Some machines will do just fine if you ignore the rules. Some machines will automatically insert padding in order to ensure that the structures and common blocks are compliant with the rules - they may or may not tell you this. The padding maybe inserted within a structure or at the end of a structure. Padding at the end makes sense in an array of structures.

The really subtle problem is that on a given machine, the fortran, c and c++ compilers may each do different things! Even worse, on a given machine the fortran compiler of one vendor may do something differently than the fortran compiler of another vendor.

These sorts of things were getting us into trouble with offline_track_struct, which is 127 4-byte words long. On Linux, Absoft Fortran automatically inserts a word of padding between array elements but gcc does not. On OSF1 and IRIX, all of fortran, gcc and g++ behave the same; so we got away with this for a long time.

[back] [fermi at work] [simulation home]

Rob Kutschke kutschke@fnal.gov