Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
HP Fortran 90 Programmer's Reference: HP Series 700/800 Computers > Chapter 10 HP Fortran 90 statements

STRUCTURE

» 

Technical documentation

» Feedback
Content starts here

 » Table of Contents

 » Glossary

 » Index

Defines a named structure. (Extension)

Syntax

STRUCTURE /struct-name/
  field-def
  ...
END STRUCTURE
struct-name

is the structure's name, delimited by slashes. struct-name can be used later to declare a record.

field-def

is a field definition.

Description

HP Fortran 90 supports the STRUCTURE statement as a compatibility extension. New programs should use the derived type, a standard feature of Fortran 90; derived types provide the same functionality as named structures. For more information about derived types, see Chapter 3 and the TYPE (declaration) statement in this chapter.

The STRUCTURE statement defines the type, size, and layout of a structure's fields, and assigns a name to the structure. Once a structure is defined, you can declare records of that structure using the RECORD statement and can manipulate the record's fields.

A structure definition pertains only to the program unit in which it is defined. For example, you cannot define a structure in the main program unit and then declare a record of that structure in a subprogram unit. Instead, the structure must be explicitly defined again in the subprogram unit.

field-def can be any of the following:

  • A type declaration statement

  • A nested structure definition

  • A nested record declaration

  • A union definition

Each type of field definition is described in the remaining sections.

Field definition as type declaration

At the simplest level, field-def can be a type declaration statement. As such, field-def has the same syntax as a standard Fortran 90 type declaration statement, except that the only attribute that can be specified is the DIMENSION attribute. A variable defined with a type declaration statement is called a field.

The following code uses simple type declaration statements to define a structure named date with three fields: month and day of type BYTE, and year of type INTEGER(KIND=2):

STRUCTURE /date/
  BYTE :: month, day
  INTEGER(KIND=2) :: year
END STRUCTURE

A type declaration statement in a structure definition can optionally define initial values for the fields. For example:

STRUCTURE /xyz/
  REAL :: x = 1.0, y = 2.0, z = 3.0
END STRUCTURE

Thereafter, any record declared of structure xyz will have its x, y, and z fields initially set to 1.0, 2.0, and 3.0 respectively. Consider the following:

RECORD /xyz/ xyz
PRINT *, xyz.x, xyz.y, xyz.z

Even though no values have been assigned to the fields of xyz with an assignment statement, the above code will display:

 1.0 2.0 3.0

Implicit typing is not allowed in a structure definition. For example, the following code would cause a compile error:

STRUCTURE /dimensions/
  x, y, z    ! illegal
END STRUCTURE

A correct way to code this would be:

STRUCTURE /dimensions/
  REAL(KIND=8) :: x, y, z    ! legal
END STRUCTURE

A field type declaration statement can also define an array, as in the following:

STRUCTURE /foo_bar/
  INTEGER foo(10)
END STRUCTURE

or, using Fortran 90 syntax:

STRUCTURE /foo_bar/
  REAL, DIMENSION(30, 50) :: bar
END STRUCTURE

The array's dimensions must in any case appear in the type statement. The DIMENSION statement (but not the DIMENSION attribute) is illegal in a structure definition. The following code defines the structure, string, which uses a type declaration statement to define an array field str of type CHARACTER(LEN=1), containing 254 elements:

STRUCTURE /string/
  CHARACTER(LEN=1) :: str(254)! Contains string
  INTEGER :: length          ! string's length
END STRUCTURE

As mentioned, the DIMENSION statement cannot be used in a structure definition. For example, the following code would cause a compile error:

STRUCTURE /real_array/
  REAL :: rarray
  DIMENSION arr(100)      ! illegal example
END STRUCTURE

A correct way to code this would be:

STRUCTURE /real_array/
  REAL :: rarray(100)
END STRUCTURE

or

STRUCTURE /real_array/
  REAL, DIMENSION(100) :: arr
END STRUCTURE

Assumed-size and adjustable arrays are also illegal in structure definitions. For example, the following is illegal:

STRUCTURE /assumed_size/  ! illegal example
  CHARACTER*(*) :: carray
END STRUCTURE

The following is also illegal:

STRUCTURE /adj_array/   ! illegal example
  INTEGER :: size
  REAL :: iarray(size)
END STRUCTURE

For alignment purposes, HP Fortran 90 provides the %FILL field name. It enables the programmer to pad a record to ensure proper alignment. The padding does not have a name and is therefore not accessible. For example, the following structure, sixbytes, creates a 6-byte structure, of which 4 bytes are inaccessible filler bytes:

STRUCTURE /sixbytes/
  INTEGER(KIND=2) :: twobytes
  CHARACTER(LEN=4) :: %FILL
END STRUCTURE

%FILL can be of any type and may appear more than once in a structure.

%FILL should not be needed in normal usage. The compiler automatically adds padding to ensure proper alignment.

Nested structures

A field-def can itself be a structure definition, known as a nested structure. The syntax of a nested structure definition is:

STRUCTURE /struct-name/struct-field-list
  field-def
  ...
END STRUCTURE
struct-name

is the structure's name (delimited by slashes), which can be used later to declare a record.

struct-field-list

is a list pf one or more names of nested structure field names separated by commas.

field-def

can be one of the following regular field definitions (defined in the same way as an unnested structure field):

  • A type declaration statement

  • Another nested structure

  • A nested record

  • A union definition

Note that a structure definition allows multiple levels of nesting.

A nested structure definition is the same as an unnested structure definition, with two exceptions:

  • /struct-name/ is optional in a nested structure.

  • A nested structure definition must include a list of one or more structure field names (struct-field-list).

If /struct-name/ is present in a nested structure definition, the structure struct-name can also be used in subsequent record declarations. For example, the following code defines a structure named person, which contains a nested structure named name. The structure's field name is nm and contains three CHARACTER*10 fields: last, first, and mid.

STRUCTURE /person/
  INTEGER :: person_id
  ! Define the nested structure 'name' with the
  !   field name 'nm'.
  STRUCTURE /name/ nm
    CHARACTER(LEN=10) :: last, first, mid
  END STRUCTURE
END STRUCTURE

Given this definition, the following code defines the record p of structure person and the record n of structure name:

RECORD /person/p
RECORD /name/n

If /struct-name/ is not present, then the structure can be used only in this declaration. For example, we could redefine the person structure so that the nested structure no longer has a name:

STRUCTURE /person/
  INTEGER :: person_id
  STRUCTURE nm
    CHARACTER(LEN=10) :: last, first, mid
  END STRUCTURE
END STRUCTURE

There is no way to declare a separate record of the nested structure because it has no name. Note, however, that the nested structure still has a field name, nm. The field name is required.

To declare an array of nested structures, simply specify a dimension declarator with the structure's field name. For example, the following structure definition contains a nested, 3-element array of structures with field name phones of structure phone:

STRUCTURE /person/
  INTEGER :: person_id
  ! Define the nested structure 'name' with the
  !   field name 'nm'.
  STRUCTURE /name/ nm
    CHARACTER(LEN=10) :: last, first, mid
  END STRUCTURE
! Nested array of structures.
  STRUCTURE /phone/ phones(3)
    INTEGER(KIND=2) :: area_code
    INTEGER :: number
  END STRUCTURE
END STRUCTURE

Nested records

A field-def can be a record declaration, known as a nested record. (See the RECORD statement in this chapter for information about record declarations.) A nested record declaration must use a structure that has already been defined. The following code first defines the structure date. It then declares the structure event, which contains the nested record when of structure date:

STRUCTURE /date/
  BYTE :: month, day
  INTEGER :: year
END STRUCTURE
STRUCTURE /event/
  CHARACTER :: what, where
  RECORD /date/ when
END STRUCTURE

A structure definition can also declare an array of nested records. For example, the following code defines the structure calendar, which contains a 100-element array of records of structure event:

STRUCTURE /calendar/
  ! number of events
  INTEGER(KIND=2) :: event_count
  ! array of event records
  RECORD /event/  events(100)
END STRUCTURE

Unions

A field-def can be a union—a form of nested structure in which two or more map blocks share memory space. The UNION and MAP statements together define a union. The syntax of a union definition is:

UNION
   map-block
   map-block
   ...
END UNION

where map-block is defined by a MAP statement and one or more field definitions. All map blocks within the enclosing UNION statement share the same memory space in a record. The syntax for defining a map block is:

MAP
   field-def
   ...
END MAP

where field-def can be one of the following:

  • A type declaration statement

  • Another nested structure

  • A nested record

  • A union definition

Note that a structure definition allows multiple levels of nesting.

For programmers who are familiar with C or Pascal, HP Fortran 90 unions are similar to unions in C and variant records in Pascal. HP Fortran 90 unions differ from C unions in that they must be defined inside a structure definition.

The structure below contains a union with two map blocks. The first contains the integer field int; the second contains the real field float.

STRUCTURE /var/
  INTEGER :: type    ! 1=INTEGER, 2=REAL
  UNION
    MAP
      INTEGER :: int
    END MAP
    MAP
      REAL :: float
    END MAP
  END UNION
END STRUCTURE

To declare a record of this structure named v, use the following RECORD statement:

RECORD /var/ v

The declaration of the record v reserves 8 bytes of storage: 4 bytes for the type field and 4 bytes to be shared by int and float. If you use the int field to access the 4 bytes, they will be interpreted as an integer; if you use the float field, they will be interpreted as a real.

It is the programmer's responsibility to ensure that appropriate values are assigned to each field in a union. For instance, given the previous declaration of v, the following assignments make sense:

v.type =1  ! set the type to integer
! access the storage shared by 'int' and 'float'
!   as an integer
v.int = 3

In contrast, the following code would yield unexpected results, although it would compile without errors:

v.type = 1  ! set the type to integer
! the next statement contradicts the previous
!   statement
v.float = 3.14

Once a value is assigned to a map block, all other map blocks become undefined. The reason is that all map blocks share memory space within a union; therefore, the values of one map block may become altered if you assign a value to a field in another map block. Consider the following definition of a structure called struct and the declaration of a record called rec:

STRUCTURE /struct/
  UNION
    MAP
      CHARACTER*8 :: s
    END MAP
    MAP
      CHARACTER*1 :: c(8)
    END MAP
  END UNION
END STRUCTURE
 
RECORD /struct/ rec

If we made the following assignment to the s field:

rec.s = 'ABCDEFGH'

and then executed the next two PRINT statements:

PRINT *, rec.s
PRINT *, rec.c

the output would be:

ABCDEFGH
ABCDEFGH

Now, if we set values in the c field and display both fields again

rec.c(1) = '1'
rec.c(8) = '8'
PRINT *, rec.s
PRINT *, rec.c

the output would be:

1BCDEFG8
1BCDEFG8

Note how the s field has changed, even though it was not directly assigned any new values. This is a result of the s and c field sharing the same storage space in the union. Although this is valid coding—that is, it will not cause a compiler or runtime error—it may cause unexpected results.

However, you can also use shared memory mapping to your benefit. The fact that map blocks share space within a union makes unions useful for equivalencing data within a record. For example, the following structure could be used to mask off individual bytes in a 4-byte word:

STRUCTURE /wordmask/
  UNION
    MAP
      INTEGER(KIND=4) :: word
    END MAP
    MAP
      BYTE :: byte0, byte1, byte2, byte3
    END MAP  END UNION
END STRUCTURE
 
RECORD /wordmask/ maskrec

If we assign a value to the word field of maskrec, we can then get the individual values of all four bytes in maskrec by looking at the fields byte0, byte1, byte2, and byte3. To see how the integer variable word maps onto the byte variables byte0, byte1, byte2, and byte3, use the following statements:

    maskrec.word = 32767
    WRITE(*, fmt=100) 'word = ', maskrec.word
    WRITE(*, 200) 'byte 0 = ', maskrec.byte0
    WRITE(*, 200) 'byte 1 = ', maskrec.byte1
    WRITE(*, 200) 'byte 2 = ', maskrec.byte2
    WRITE(*, 200) "byte 3 = ', maskrec.byte3
100 FORMAT(A, Z8.8)
200 FORMAT(A, Z2.2)

This code displays the following output:

word = 00007FFF
byte 0 = 00
byte 1 = 00
byte 2 = 7F
byte 3 = FF

Such code, depending as it does on a specific word size, is inherently nonportable.

Related statements

RECORD and TYPE

Related concepts

Derived Types are described in Chapter 3.

Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© 1996 Hewlett-Packard Development Company, L.P.