8.1 Structures

---------------

8.1.1 What is a structure?

~~~~~~~~~~~~~~~~~~~~~~~~~~~

A structure is a collection of one or more variables, possibly of

different types, grouped together under a single name for convenient

handling.

8.1.2 Syntax

~~~~~~~~~~~~~

struct [<tag>] { <list-of-declarations-of-elements> }

<specifier>[,<specifier>...];

struct <tag> <specifier> [,<specifier>];

Declaration of a structure begins with the keyword 'struct'. It can

be written in two forms.

In the first form, the types and names of elements of the structure

are specified in list-of-declarations-of-elements. In this case <tag> is

optional. This is an identifier which names the structural type defined

by the list of declarations of elements. The <specifier> specifies either

a variable of structure type or an array of structures of this type.

The second form of syntax of the declaration uses a structure tag to

refer to the structure type defined somewhere else in the program.

The list of declarations of elements is a sequence of one or more

declared variables. Each variable declared in this list is called a

structure element.

Structure elements are written to memory sequentially in the order in

which they are declared. By default there is no alignment of elements

within a structure, but you can use the command-line option (switch) to

align within a structure. The structure itself is aligned to an even

address if alignment is switched on.

Examples of structure declarations:

struct test

{

int a;

char b[8];

long c;

} rr, ff[4];

This example declares a structure 'rr' and an array of four

structures 'ff'. The tag 'test' is assigned to the entire set of

variables. This tag can be used to declare other structures, for example:

struct test dd;

This declares a structure 'dd' with a set of elements declared in the

tag 'test'.

When declaring a structure with a previously declared tag, the

keyword 'struct' need not be written, so that you can write:

8.1.3 Initializing structures at compilation

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After a structure is declared, its elements can have any value. To

avoid the need for this, structures must be initialized. Only global

structures can be initialized after they are declared. C-- supports

several methods of initializing a structure at declaration:

1. Single value:

struct test dd=2;

In this example, the value 2 is assigned to all elements.

2. Array of values

struct test dd={1,2,,6};

In this example the first element of structure 'dd' is assigned the

value 1, the second 2, and the fourth 6. Values skipped and not

initialized are assigned 0.

3. Command FROM:

struct test dd=FROM "file.dat";

In this example, the contents of <file.dat> are loaded during

compilation to the place where structure 'dd' was located. If the file is

larger than the structure, excess bytes will be loaded into program code

but they will not be used. If the file is smaller than the structure, the

empty bytes of the structure will be filled with zeros.

4. Command EXTRACT:

struct test dd=EXTRACT "file.dat", 24, 10;

In this example a fragment of <file.dat> is loaded during compilation

to the place where structure 'dd' was located. If the file is larger than

the structure, excess bytes will be loaded into program code but they

will not be used. If the file is smaller than the structure, the empty

bytes of the structure will be filled with zeros.

8.1.4 Initializing structures at run time

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When a program is executed, in addition to assigning each member of a

structure a value, one can initialize the entire structure by assigning

it a number or a variable. For example:

void proc()

struct test aa[5],rr;

int i;

{

aa[0]=0x12345678;

aa[i]=int 0x12345678;

aa=long 0x12345678;

rr=i;

In the first example, memory occupied by the first structure of an

array of five structures is filled with byte 0x78 (by default).

In the second example, memory occupied by the (i+1)st structure of an

arrawy of five structures is filled with word 0x5678.

In the third example memory occupied by an entire array of five

structures is filled with long word 0x12345678.

In the fourth example memory occupied by structure 'rr' is filled with

the contents of variable i.

The contents of one structure can be copied to another structure. For

example:

rr=aa[2];

The contents of the third structure of an array of structures 'aa' is

copied to structure 'rr'.

8.1.5 Operations on structure members

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Operations available on a structure member are the operations

available for a variable of that type. For example (a declared

structure):

struct test

{

int a;

char b[8];

long c;

} rr[3];

Example of permissible syntax:

rr.a = rr.b[i] * rr[1].c + i ;

Note:

For operations on members of an array of structures, or structures

with indexed members in which a variable is used as the index or

structure number, the compiler can use registers SI or DI, and in some

situations (for instance rr[i].b[j] >< rr[i+1].b[j+2] ) register DX is

also used.

For individual structure members their address, size and offset in

the structure tag can be obtained. For example:

struct AA // declaration of structure tag

{

word a[3]; // first structure member

char b; // second structure member

long c; // third structure member

};

struct BB //second structure tag

{

word aa; // first element

AA bb; // second element - embedded structure

}ss; // declare structure with tag BB

void proc()

{

AX=#ss.bb.b; // get address of member 'b' of structure 'bb' in structure 'ss'

AX=#BB.bb.b; // get offset of this member in tag 'BB'

AX=sizeof(ss.bb); // get size of member 'bb' of structure 'ss'

AX=sizeof(BB.bb); // get size of member 'bb' in tag 'BB'

}

8.1.6 Embedded structures

~~~~~~~~~~~~~~~~~~~~~~~~~~

Tags of previously declared structures can be used when declaring a

structure. Here is an example of an embedded structure:

struct RGB

{

byte Red;

byte Green;

byte Blue;

byte Reserved;

};

struct BMPINFO

{

struct BMPHEADER header; //description this structure is missed

struct RGB color[256];

}info;

description of this structure is omitted

Let's assume that you need to get the contents of the variable Red

of the tenth color member, which can be written:

AL=info.color[10].Red;

There is one limit on the use of embedded structures in C--. A

variable cannot be used as an index more than once where referring to

multiple-copy structures. This can be illustrated on the following

example:

struct ABC

{

int a;

int b;

int c;

};

struct

{

struct ABC first[4]; //four copies of structure ABC

int d;

}second[4];

int i,j;

void proc()

{

AX=second[i].first[j].a; //such record will cause report on error, so

//as variable was used in two places

AX=second[2].first[j].a; //but this syntax possible.

AX=second[i].first[3].a;

}

this will produce an error message since the variable is used in two

places but this syntax is valid

8.1.7 Mapping a structure tag to a memory block

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Mapping a structure tag to a memory block is an alternate pointer to

the structure.

This alternate way of using pointers to structures lets the

programmer choose the register where the structure address is to be

stored, and to check its integrity and if needed to restore its contents.

The following example illustrates how to map a structure tag to

memory:

struct AA //declare structure tag

{

word a[3]; // first structure member

char b; // second structure member

long c; // third structure member

};

byte buf[256]; //memory block to which structure tag is mapped

void proc1()

{

...

proc2 ( #buf ); // call function and transfer it as a parameter of

// memory block address

...

}

long proc2 (unsigned int pointer_to_mem)

{

int i;

BX=pointer_to_mem; // load memory block address to BX

FOR(i=0; i<3; i++){ // write -1 to array of member 'a'

BX.AA.a[i]=-1;

}

BX.AA.b=0;

ES:BX.AA.c=EAX;

return BX.AA.c; // return contents of member 'c'

}

In 16-bit mode registers BX, DI, SI and BP can be used to store the

address of a structure, but it is best to use BX. Registers DI and SI

can be used to calculate the address of multi-member objects. Register BP

is used to work with local and parametric variables. In 32-bit mode any

register can be used except ESP and EBP, but registers EDI and ESI must

be used with caution.

8.1.8 Bit fields in structures

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Bit fields of structures are used to save memory since they can be

used to pack values tightly and to organize convenient access to

registers of external devices in which different bits can have

independent functionality.

Bit fields are declared using the following syntax:

<type> [<identifikator>]:<constanta>;

for example:

int var:5; //declare bit field of size 5 bits named 'var'

A bit field consists of a certain number of bits which is assigned a

numeric expression <constant>. This value must be a positive integer and

its value cannot except the number of bytes corresponding to the <type>

of the defined bit field. In C-- bit fields can contain only unsigned

values. Arrays of bit fields or pointers to bit fields cannot be used.

The <identifier> names the bit field and is required. An unnamed bit

field is a gap corresponding to the number of bits before the position of

the next structure member. An unnamed bit field for which zero size is

specified has a special purpose: it guarantees that memory for the next

bit field will begin at the boundary of the type specified for the

unnamed bit field, i. e., the bit field will be aligned to 8/16/32 bits.

In C-- all bit fields are packed one after the other despite the

boundaries of identifier types. If the next field is not a bit field, the

bits remaining to the boundary of the byte will not be used. The maximum

size of a bit field is 32 bits for type 'dword' or 'long', 16 bits for

type 'word' or 'int', and 8 bits for type 'byte' or 'char'. Bit fields

can be combined, or used in the operater 'union'. Doing 'sizeof' a bit

field returns the size of the field in bits. When a bit field is used,

its contents will be extended to the register, along with an unsigned

integer.