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
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):
A type declaration statement in a structure definition can
optionally define initial values for the fields. For example:
REAL :: x = 1.0, y = 2.0, z = 3.0 |
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:
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:
Implicit typing is not allowed in a structure definition.
For example, the following code would cause a compile error:
A correct way to code this would be:
REAL(KIND=8) :: x, y, z ! legal |
A field type declaration statement can also define an array,
as in the following:
or, using Fortran 90 syntax:
REAL, DIMENSION(30, 50) :: bar |
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:
CHARACTER(LEN=1) :: str(254)! Contains string |
INTEGER :: length ! string's length |
As mentioned, the DIMENSION
statement cannot be used in a structure definition. For example,
the following code would cause a compile error:
DIMENSION arr(100) ! illegal example |
A correct way to code this would be:
or
REAL, DIMENSION(100) :: arr |
Assumed-size and adjustable arrays are also illegal in structure
definitions. For example, the following is illegal:
STRUCTURE /assumed_size/ ! illegal example |
The following is also illegal:
STRUCTURE /adj_array/ ! illegal example |
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:
INTEGER(KIND=2) :: twobytes |
CHARACTER(LEN=4) :: %FILL |
%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
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.
! Define the nested structure 'name' with the |
CHARACTER(LEN=10) :: last, first, mid |
Given this definition, the following code defines the record
p of structure
person and the
record n of structure
name:
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:
CHARACTER(LEN=10) :: last, first, mid |
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:
! Define the nested structure 'name' with the |
CHARACTER(LEN=10) :: last, first, mid |
! Nested array of structures. |
STRUCTURE /phone/ phones(3) |
INTEGER(KIND=2) :: area_code |
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:
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:
INTEGER(KIND=2) :: event_count |
RECORD /event/ events(100) |
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
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.
INTEGER :: type ! 1=INTEGER, 2=REAL |
To declare a record of this structure named v,
use the following RECORD
statement:
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' |
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 |
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:
If we made the following assignment to the s field:
and then executed the next two PRINT statements:
the output would be:
Now, if we set values in the c
field and display both fields again
the output would be:
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:
BYTE :: byte0, byte1, byte2, byte3 |
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:
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 |
This code displays the following output:
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.