Declares a user-defined type.

Type typename
fieldname1 As DataType
fieldname2 As DataType
As DataType fieldname3, fieldname4
End Type

Type typename [Extends base_typename] [Field = alignment]

Declare Sub|Function|Constructor|Destructor|Property|Operator ...
Static variablename As DataType

fieldname As DataType [= initializer]
fieldname(array dimensions) As DataType [= initializer]
fieldname(Any [, Any...]) As DataType
fieldname : bits As DataType [= initializer]

As DataType fieldname [= initializer], ...
As DataType fieldname(array dimensions) [= initializer], ...
As DataType fieldname(Any [, Any...])
As DataType fieldname : bits [= initializer], ...

fieldname As DataType
fieldname As DataType
End Type
End Union

End Type

Type is used to declare custom data types containing one or more data fields, including integer types, floating point types, fixed-size or variable-length (dynamic) arrays, fixed-size or variable-length strings, bitfields, or other user-defined types.

Types support various functionality related to object-oriented programming:

Types may also contain nested types or unions, allowing data members to be grouped as desired. Nested types/unions are not allowed to contain member procedures or static member variables (same restriction for local types/unions).

Memory layout
Types lay out their fields consecutively in memory, following the native alignment and padding rules (described on the Field page). Special care must be taken when using Types for file I/O or interacting with other programs or programming languages, in case the alignment and padding rules are different. The optional Field = number specifier can be used to change the behavior on the FreeBASIC side.

Variable-length data
In FreeBASIC, Type data structures must ultimately be fixed-size, such that the compiler knows how much memory to allocate for objects of that Type. Nevertheless, Types may contain variable-length (dynamic) string or array data members. However, the string's/array's data will not be embedded in the Type directly. Instead, the Type will only contain a String/array descriptor structure, which FreeBASIC uses behind the scenes to manage the variable-length string/array data. For sizing the structure of the array descriptor in the Type, a variable-length (dynamic) array data member must be always declared by using Any(s) in place of the array bounds, in order to fix the amount of dimensions based on the number of Anys specified.

Because of that, saving such a Type into a file will write out the descriptor, not the actual string/array data. In order to embed strings/arrays into Types directly, fixed-length strings/arrays must be used.

Similarly, when maintaining dynamic data manually through the use of pointers within a Type, it does usually not make sense to save the Type to a file, because the address stored in the pointer field will be written to file, not the actual memory it points to. Addresses are meaningful to a specific process only though, and cannot be shared that way.

Special note on fixed-length strings
Currently, fixed-length string fields of String * N type have an extra null terminator at their end, for compatibility with C strings, making them incompatible with QB strings inside Types, because they actually use up N+1 bytes, instead of just N bytes. A possible work-around is to declare the field As String * (N-1), though this will not work in future releases if the null terminator is removed. Another alternative is to use a Byte or UByte array with the proper size.

Note on bitfields ( fieldname : bits )
Bitfields can only be declared inside a type or a union, and allow to specify some very small objects of a given number of bits in length. Each field is accessed and manipulated as if it were an ordinary member of the structure. Only integer data-types (up to 32-bit for 32-bit development or 64-bit for 64-bit development) are valid. The sizes of the declared data-types, large enough to contain the bit patterns, affect how the bitfields are placed in memory.
A bitfield does not have any address (one cannot get a pointer to it and its offset inside the structure).

This is an example of a QB-style type, not including procedure definitions
Type clr
    red As UByte
    green As UByte
    blue As UByte
End Type

Dim c As clr
c.red = 255
c.green = 128
c.blue = 64

And this is an example of a type working as an object:
'' Example showing the problems with fixed length string fields in UDTs
'' Suppose we have read a GIF header from a file
''                        signature         width        height
Dim As ZString*(10+1) z => "GIF89a" + MKShort(10) + MKShort(11)

Print "Using fixed-length string"

Type hdr1 Field = 1
   As String*(6-1) sig /' We have to dimension the string with 1 char
                        '  less to avoid misalignments '/
   As UShort wid, hei
End Type

Dim As hdr1 Ptr h1 = CPtr(hdr1 Ptr, @z)
Print h1->sig, h1->wid, h1->hei '' Prints GIF89 (misses a char!)  10  11

'' We can do comparisons only with the 5 visible chars and creating a temporary string with LEFT

If Left(h1->sig, 5) = "GIF89" Then Print "ok" Else Print "error"

'' Using a ubyte array, we need an auxiliary function to convert it to a string
Function ub2str( ub() As UByte ) As String
    Dim As String res = Space(UBound(ub) - LBound(ub) + 1)
    For i As Integer = LBound(ub) To UBound(ub)
        res[i - LBound(ub)] = ub(i)
    Function = res
End Function

Print "Using an array of ubytes"

Type hdr2 Field = 1
   sig(0 To 6-1) As UByte '' Dimension 6
   As UShort wid, hei
End Type

Dim As hdr2 Ptr h2 = CPtr(hdr2 Ptr, @z)
'' Viewing and comparing is correct but a conversion to string is required

Print ub2str(h2->sig()), h2->wid, h2->hei '' Prints GIF89a  10  11 (ok)
If ub2str(h2->sig()) = "GIF89a" Then Print "ok" Else Print "error" '' Prints ok

This is an example of conversion from an Ubyte to a digit string in base 8 (octal string), by using bitfields in a local UDT (conversion equivalent to 'Oct(x, 3)'):
Function UbyteToOctalString (ByVal b As UByte) As String
    Union UbyteOctal
        number As UByte
            d0 : 3 As UByte
            d1 : 3 As UByte
            d2 : 2 As UByte
        End Type
    End Union
    Dim uo As UbyteOctal
    uo.number = b
    Return uo.d2 & uo.d1 & uo.d0
End Function

For I As Integer = 0 To 255
    Print Using "###: "; I;
''    Print Oct(I, 3),
    Print UbyteToOctalString(I),  '' this line is thus equivalent to the previous one
Next I


Platform Differences:

Dialect Differences:
Differences from QB:
See also:
Back to User Defined Types
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki

sf.net phatcode