Announcement

Collapse
No announcement yet.

Type End Type Block

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Type End Type Block

    Please add your comments and suggestions as a Reply to this thread.





    PB/WIN - TYPE/END TYPE block

    Purpose
    Define a User-Defined Data Type (UDT), containing one or more member elements.
    Syntax
    TYPE MyType [BYTE | WORD | DWORD | QWORD] [FILL]
    [MemberName [(subscripts)] AS] TypeName
    [MemberName [(subscripts)] AS TypeName]
    [...]
    END TYPE
    Remarks
    The TYPE statement has the following parts:
    TYPE
    The beginning of a User-Defined Type definition.
    MyType
    The name of the User-Defined Type, which must conform to standard variable naming conventions.
    Member alignment
    TYPE definitions may optionally specify an alignment of BYTE (the default), WORD, DWORD, or QWORD, as well as FILL characteristics. With standard alignment, each member of a Type Structure will be located on the specified boundary. For example, with DWORD, up to 3 bytes may be skipped between members to accomplish alignment.

    However, when a user-defined type is defined as a member of a larger user-defined type, this "sub-type" retains its original size and alignment, just as first declared.
    BYTE
    Each member will be aligned on a BYTE boundary - no padding or alignment is applied to the structure. This is the default alignment method.
    WORD
    Each member will be aligned on a WORD boundary. Any odd byte between members of TYPE will be automatically skipped and ignored. The UDT structure may also be padded with one trailing byte to ensure the total structure size is a multiple of 2 bytes.
    DWORD
    Each member will be aligned on a DWORD boundary. Up to three bytes will be skipped to accomplish this alignment. The UDT structure is also padded with up to three trailing bytes to ensure the total structure size is a multiple of 4 bytes.
    QWORD
    QWORD alignment is included for compatibility with Windows, it cannot be fully implemented in a 32-bit operating system. With QWORD, individual members are 64-bit aligned for the appropriate structure size, but variables of that type may only be aligned on 32-bit boundaries, as stack pointer alignment is not guaranteed.
    FILL
    If the FILL option is specified, such as TYPE xxx DWORD FILL, the following rules apply:

    1. No bytes are skipped if the next member of the Type will fit entirely into that space to be skipped.

    2. Fixed-length strings are considered to be an array of bytes, so no bytes are skipped preceding them.

    3. The total size of an array is considered to determine if FILL should affect its placement within the structure. For example, with DWORD FILL, an array of two integers would be started on a 4-byte boundary, even if two or three bytes must be skipped.
    Type members
    MemberName
    The name of a member of the User-Defined Type. This too must follow the standard variable naming conventions.
    subscripts
    The dimensions of a member array. Arrays of one and two dimensions are supported, but must be defined with constant or numeric literal values. That is, the total size of a UDT must be known at compile-time, so items like dynamic strings, which vary in size, cannot be part of a TYPE structure. A STRING PTR can, however, since a pointer is implemented as a DWORD.

    Like conventional arrays, the default lower array boundary is zero, but positive non-zero values may be used to specify a specific range of subscript index values for the array, separated from the upper array boundary subscript with the TO keyword. Additionally, both the lower and upper subscript index values must be zero or greater (ie, negative subscript values are not permitted). Examples of valid syntax follow:

    Code:
    TYPE MYTYPE
      id AS INTEGER              ' Scalar UDT member
      Styles(6)         AS DWORD '  7 elements (0 TO 6)
      Yrs(1980 TO 2010) AS LONG  ' 31 elements
      Team(100 TO 101)  AS BYTE  '  2 elements
      Rating(1 TO 10)   AS DWORD ' 10 elements
      X(1 TO 5, 0 TO 5) AS EXT   ' 30 elements (5x6)
      Y(4,3)            AS QUAD  ' 20 elements (5x4)
    END TYPE
    Individual UDT structures can be up to 16 MB each. A single member element of a UDT may also occupy the entire 16 MB. For example, arrays within a UDT, nul-terminated strings, and fixed-length strings. UDT member arrays are not resizable at runtime. Additionally, the ARRAY statements cannot be used directly on a UDT member array. Instead, use DIM..AT to declare a conventional array at the same memory address as the UDT member array, and the ARRAY statement can then be used on that array.
    TypeName
    One of the supported data types, including User-Defined Types and Unions, with the exception of arrays.
    END TYPE
    Marks the end of the User-Defined Type definition.

    It is often very convenient to be able to refer to several different types of things as a single unit or data structure. For example, in an accounting program, an account number and amount are part of what makes up a single journal entry. The TYPE/END TYPE block statements make it easy to create a single UDT that holds such information.

    Code:
    TYPE JournalType DWORD   ' type name and alignment
      AccountNumber AS LONG  ' member name and data type
      Amount        AS CUR   ' this is another one
    END TYPE                 ' end of type declaration
    DIM JournalEntry AS JournalType ' declare a record
    TYPE/END TYPE blocks must be defined outside of a Sub, Function, or Class and may be defined only once in any program. It is usually easiest to put your TYPE/END TYPE block definitions in an Include file and use the #INCLUDE metastatement in any module that may need to use them.

    TYPE/END TYPE blocks do not declare any variables; instead, they simply define a new type. You can declare variables of that type using the DIM or REDIM statements, or any statement that lets you use an AS clause:

    Code:
    DIM TypeVariable as TypeVariableType
    Once you have a User-Defined Type variable declared, you can access its member elements using the following format:

    Code:
    TypeVariable.Element
    For example, to change the account number in the JournalEntryType type, you might use a statement like:

    Code:
    JournalEntry.AccountNumber = 1000
    A User-Defined Type can be used like any built-in PowerBASIC type. For example, you can define an array of record variables:

    Code:
    DIM JournalEntries(1 TO 100) AS JournalEntryType
    …or even create a procedure that accepts a record variable:

    Code:
    SUB PrintJournalEntry(aJournalEntry AS JournalEntryType)
      ' Print journal
    END SUB
    You can also use pointers in a TYPE definition. Note that the first member in the next example is auto-aligned to start on a DWORD boundary, and three bytes are skipped so that the second member is also aligned on a DWORD boundary:

    Code:
    TYPE MyType DWORD
      Count AS BYTE    ' Aligned to a DWORD boundary
      y AS INTEGER PTR ' Aligned to next DWORD boundary
      z AS STRING PTR
    END TYPE
    Since pointers are stored as a DWORD, their length is 4 bytes when used in a TYPE/END TYPE, regardless of the length of their target. To access the target of a pointer, you must place the at-sign in front of the TYPE/END TYPE member, not the name of the TYPE itself:

    Code:
    iResult% = @MyType.y    ' Invalid
    iResult% = [email protected]    ' Valid
    You can also declare a variable that is a pointer to a TYPE:

    Code:
    TYPE MyData
      Val1 AS INTEGER
      Val2 AS INTEGER
      Val3 AS INTEGER
      Val4 AS INTEGER
    END TYPE
    DIM Info AS MyData PTR
    Info = VARPTR(YourData)
    Message$ = HEX$(@Info.Val1) + $CRLF + _
               HEX$(@Info.Val2) + $CRLF + _
               HEX$(@Info.Val3) + $CRLF + _
               HEX$(@Info.Val4)
    Note that the target specifier is in front of the TYPE name since it is the pointer. Val1, Val2, Val3, and Val4 represent offsets from that pointer. PowerBASIC does support a pointer within a structure pointer, but you should be very careful in their use. Changing the structure pointer itself could make all member pointers invalid. See the topic on pointers for more information.
    Bit Variables
    TYPE structures may contain bit variables, which are named BIT (unsigned values) or SBIT (signed values). Each bit variable may occupy from 1 to 31 bits, and they may be packed one after another up to a total of 32 bits per bit field. The size of a bit variable is defined as follows:

    Code:
    var AS BIT * nlit [IN BYTE|WORD|DWORD]
    …where the term "* nlit" defines the number of bits (1 to 31), and the optional term "IN BYTE|WORD|DWORD", if present, defines the start of a new bit field of 1, 2, or 4 bytes. For example:

    Code:
    TYPE ABCD
      Valu2 AS BIT  * 31 IN DWORD
      Sign1 AS SBIT * 1
      nybl2 AS BIT  * 4 IN BYTE
      nybl1 AS BIT  * 4
    END TYPE
    The example TYPE structure above is 5 bytes in size, containing a 4-byte bit field and a 1-byte bit field. In this case, each contains two bit-variables of varying size. The range of values which may be stored depends upon the number of bits available. For example, "BIT * 4" has a range of 0 to 15, "SBIT * 1" has a range of -1 to 0, and "SBIT * 5" has a range of -16 to +15.
    Structures within structures
    Structures (TYPE/UNION) may be embedded within another structure, for simplification in referencing deeply nested items, by simply stating the structure name alone at the appropriate position. The internal alignment of the member structure is precisely maintained regardless of other alignment specifications, to foster inheritance issues. For example:
    TYPE ABCD3
    A AS LONG
    ABCD2
    C AS LONG
    END TYPE
    TYPE ABCD2
    D AS DWORD
    E AS DOUBLE
    ABCD1
    END TYPE
    UNION ABCD1
    F AS DWORD
    G AS LONG
    H AS SINGLE
    END UNION
    In this case, you could access the lone Single-precision float member of this structure very simply. Assuming DIM X AS ABCD3, you could reference the Single-precision Union member with the statement X.H, instead of the extended syntax X.ABCD2.ABCD1.H
    For related information, please refer to the UNION/END UNION and User-Defined Types and Unions sections.
    Restrictions
    When measuring the size of a padded (aligned) UDT structure with the LEN or SIZEOF statements, the measured length includes any padding that was added to the structure. For example, the following UDT structure:

    Code:
    TYPE LengthTestType DWORD
      a AS INTEGER
    END TYPE
    ' more code here
    DIM abc AS LengthTestType
    x& = LEN(abc)
    Returns a length of 4 bytes in x&, since the UDT was padded with 2 additional bytes to enforce DWORD alignment. Note that the LEN and SIZEOF of individual UDT members will return the true size of the member without regard to padding or alignment. In the previous example, LEN(abc.a) returns 2.

    Individual UDT structures can be up to 16 MB each. Arrays within a UDT, nul-terminated strings and fixed-length strings may occupy the full 16 MB structure size limit.

    Field strings and dynamic strings cannot be used in UDT or UNION structures. Attempting to do so results in a compile-time Error 485 ("Dynamic/Field strings not allowed").
    See AlsoReferencesExamples
    Code:
    TYPE JournalEntryType
      AccountName    AS STRING * 20
      AccountNumber  AS LONG
      Amount         AS CUR
    END TYPE
    DIM JournalEntry AS JournalEntryType
    JournalEntry.AccountName   = "Joe Smith"
    JournalEntry.AccountNumber = 7467047&
    JournalEntry.Amount        = [email protected]
    ' process journal entry here
    JournalEntry.AccountNumber = 705233476&
    JournalEntry.Amount        = [email protected]
    ' process journal entry here
    Last edited by Gary Beene; 28 Oct 2014, 10:44 PM.
Working...
X