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.