5.2.2 Defining Structure and Union Variables

Once you have declared a structure or union type, variables of that type can be defined. For each variable defined, memory is allocated in the current segment in the format declared by the type. The syntax for defining a structure or union variable is:

[[name]] typename< [[initializer[[,initializer]]...]] >

[[name]] typename{ [[initializer[[,initializer]]...]] }

[[name]] typename constantDUP ({ [[initializer[[,initializer]]...]] })

The name is the label assigned to the variable. If no name is given, the assembler allocates space for the variable but does not give it a symbolic name. The typename is the name of a previously declared structure or union type.

An initializer can be given for each field. The type of each initializer must be the type of the corresponding field defined in the type declaration. For unions, the type of the initializer must be the same as the type for the first field. An initialization list can also be repeated using the DUP operator.

The list of initializers can be broken only after a comma unless you use a line continuation character (\) at the end of the line. The last curly brace or angle bracket must appear on the same line as the last initializer. You can also use the line continuation character to extend a line as shown in the Item4 declaration below. Angle brackets and curly braces can be intermixed in an initialization as long as they match. This example using the ITEMS structure illustrates the options for initializing lists:<$I<< \ra (angle brackets);structures and unions>

ITEMS STRUCT

Iname BYTE 'Item Name'

Inum WORD ?

ITYPE UNION

oldtype BYTE 0

newtype WORD ?

ENDS

ITEMS ENDS

.

.

.

.DATA

Item1 ITEMS < > ; Accepts default initializers

Item2 ITEMS { } ; Accepts default initializers

Item3 ITEMS <'Bolts', 126> ; Overrides default value of first

; 2 fields; use default of

; the third field

Item4 ITEMS { \

'Bolts', ; Item name

126 \ ; Part number

}

The angle brackets or curly braces are required even if no initial value is given, as in Item1 and Item2 in the example. If initial values are given for more than one field, the values must be separated by commas, as shown in Item3.

You need not initialize all fields in a structure. If an initial value is blank, the assembler automatically uses the default initial value of the field, which was originally provided in the structure type declaration. If there is no default value, the field is undefined.

For nested structures or unions (see Section 5.2.4), however, these are equivalent:

Item5 ITEMS {'Bolts', , }

Item6 ITEMS {'Bolts', , { } }

A variable and an array of union type WB look like this:

WB UNION

w WORD ?

b BYTE ?

WB ENDS

num WB {0Fh} ; Store 0Fh

array WB (40 / SIZEOF WB) DUP ({2}) ; Allocates and

; initializes 10 unions

In MASM 6.0, control structures (such as IF, macros, and directives) are also allowed within structure and union declarations.

Arrays as Field Initializers

Summary: Default initializers for string or array fields set the size for the field.

The length of the array that can override the contents of a field in a variable definition is fixed by the size of the initializer. The override cannot contain more elements than the default. Specifying fewer override array elements changes the first n values of the default where n is the number of values in the override. The rest of the array elements take their default values from the initializer.

Strings as Field Initializers

If the override is shorter, the assembler pads the override with spaces to equal the length of the initializer. If the initializer is a string and the override value is not a string, the override value must be enclosed in angle brackets or curly braces.

A string may be used to override any member of type BYTE (or SBYTE). The string does not need to be enclosed in angle brackets or curly braces unless mixed with other override methods.

Summary: The string fields for structure variables are the length defined by the type declaration.

If a structure has an initialized string field or an array of bytes, any new string assigned to a variable of the field that is smaller than the default is padded with spaces. The assembler adds four spaces at the end of 'Bolts' in the variables of type ITEMS above. The Iname field in the ITEMS structure cannot contain a field initializer longer than 'Item Name'.

Structures as Field Initializers

Initializers for structure variables must be enclosed in curly braces or angle brackets, but you can specify overrides with fewer elements than the defaults.

This example illustrates the use of default values with structures as field initializers:

DISKDRIVES STRUCT

a1 BYTE ?

b1 BYTE ?

c1 BYTE ?

DISKDRIVES ENDS

INFO STRUCT

buffer BYTE 100 DUP (?)

crlf BYTE 13, 10

query BYTE 'Filename: ' ; String <= can override

endmark BYTE 36

drives DISKDRIVES <0, 1, 1>

INFO ENDS

info1 INFO { , , 'Dir' }

; Illegal since name in query field is too long

; and a string cannot initialize a field defined with DUP:

; info2 INFO {"TESTFILE", , "DirectoryName",}

lotsof INFO { , , 'file1', , {0,0,0} },

{ , , 'file2', , {0,0,1} },

{ , , 'file3', , {0,0,2} }

The diagram below shows how the assembler stores info1.

The initialization for drives gives default values for all three fields of the structure. The fields left blank in info1 use the default values for those fields. The info2 declaration is illegal since “DirectoryName” is longer than the initial string for that field, and the "TESTFILE" string cannot initialize a field defined with DUP.

Arrays of Structures and Unions

You can define an array of structures using the DUP operator (see Section 5.1.1, “Declaring and Referencing Arrays”) or by creating a list of structures. For example, you can define an array of structure variables like this:

Item7 ITEMS 30 DUP ({,,{10}})

The Item7 array defined here has 30 elements of type ITEMS, with the third field of each element (the union) initialized to 10.

You can also list array elements as shown in this example:

Item8 ITEMS {'Bolts', 126, 10},

{'Pliers',139, 10},

{'Saws', 414, 10}

Structure Redefinition

The assembler generates an error for a structure redefinition unless all of the following are the same:

Field names

Offsets of named fields

Initialization lists

Field alignment value

Additionally, all fields must be present and at the same offset.

LENGTHOF, SIZEOF, and TYPE for Structures

The size of a structure determined by SIZEOF is the offset of the last field, plus the size of the last field, plus any padding required for proper alignment (see Section 5.2.1 for information about alignment). This example, using the data declarations above, shows how to use the LENGTHOF, SIZEOF, and TYPE operators with structures:

INFO STRUCT

buffer BYTE 100 DUP (?)

crlf BYTE 13, 10

query BYTE 'Filename: '

endmark BYTE 36

drives DISKDRIVES <0, 1, 1>

INFO ENDS

info1 INFO { , , 'Dir' }

lotsof INFO { , , 'file1', , {0,0,0} },

{ , , 'file2', , {0,0,1} },

{ , , 'file3', , {0,0,2} }

sinfo1 EQU SIZEOF info1 ; 116 = number of bytes in

; initializers

linfo1 EQU LENGTHOF info1 ; 1 = number of items

tinfo1 EQU TYPE info1 ; 116 = same as size

slotsof EQU SIZEOF lotsof ; 116 * 3 = number of bytes in

; initializers

llotsof EQU LENGTHOF lotsof ; 3 = number of items

tlotsof EQU TYPE lotsof ; 116 = same as size for structure

; of type INFO

LENGTHOF, SIZEOF, and TYPE for Unions

The size of a union determined by SIZEOF is the size of the longest field plus any padding required. The length of a union variable determined by LENGTHOF equals the number of initializers defined inside angle brackets or curly braces. TYPE returns a value indicating the type of the longest field.

DWB UNION

d DWORD ?

w WORD ?

b BYTE ?

DWB ENDS

num DWB {0FFFFh}

array DWB (100 / SIZEOF DWB) DUP ({0})

snum EQU SIZEOF num ; = 4

lnum EQU LENGTHOF num ; = 1

tnum EQU TYPE num ; = 4

sarray EQU SIZEOF array ; = 100 (4*25)

larray EQU LENGTHOF array ; = 25

tarray EQU TYPE array ; = 4