Structures


Syntax
Structure <name> [Extends <name>] [Align <numeric constant expression>]
  ...
EndStructure 
Description
Structure is useful to define user type, and access some OS memory areas. Structures can be used to enable faster and easier handling of data files. It is very useful as you can group into the same object the information which are common. Structures fields are accessed with the \ option. Structures can be nested. Statics arrays are supported inside structures.

Dynamic objects like arrays, lists and maps are supported inside structure and are automatically initialized when the object using the structure is created. To declare such field, use the following keywords: Array, List and Map.

The optional Extends parameter allows to extends another structure with new fields. All fields found in the extended structure will be available in the new structure and will be placed before the new fields. This is useful to do basic inheritance of structures.

For advanced users only. The optional Align parameter allows to adjust alignment between every structure field. The default alignment is 1, meaning no alignment. For example, if the alignment is set to 4, every field offset will be on a 4 byte boundary. It can help to get more performance while accessing structure fields, but it can use more memory, as some space between each fields will be wasted. The special value #PB_Structure_AlignC can be used to align the structure as it would be done in language C, useful when importing C structures to use with API functions.

SizeOf can be used with structures to get the size of the structure and OffsetOf can be used to retrieve the index of the specified field.

Please note, that in structures a static array[] doesn't behave like the normal BASIC array (defined using Dim) to be conform to the C/C++ structure format (to allow direct API structure porting). This means that a[2] will allocate an array from 0 to 1 where Dim a(2) will allocate an array from 0 to 2. And library functions Array don't work with them.

When using pointers in structures, the '*' has to be omitted when using the field, once more to ease API code porting. It can be seen as an oddity (and to be honest, it is) but it's like that since the very start of PureBasic and many, many sources rely on that so it won't be changed.

When using a lot of structure fields you can use the With : EndWith keywords to reduce the amount of code to type and ease its readability.

It's possible to perform a full structure copy by using the equal affectation between two structure element of the same type.

ClearStructure can be used to clear a structured memory area. It's for advanced use only, when pointers are involved.

Example

  Structure Person
    Name.s
    ForName.s 
    Age.w 
  EndStructure

  Dim MyFriends.Person(100)

  ; Here the position '0' of the array MyFriend()
  ; will contain one person and it's own information

  MyFriends(0)\Name = "Andersson"
  MyFriends(0)\Forname = "Richard" 
  MyFriends(0)\Age = 32

Example: A more complex structure (Nested and static array)

  Structure Window
    *NextWindow.Window  ; Points to another window object
    x.w 
    y.w
    Name.s[10]  ; 10 Names available (from 0 to 9)
  EndStructure

Example: Extended structure

  Structure MyPoint
    x.l 
    y.l
  EndStructure

  Structure MyColoredPoint Extends MyPoint
    color.l 
  EndStructure

  ColoredPoint.MyColoredPoint\x = 10
  ColoredPoint.MyColoredPoint\y = 20
  ColoredPoint.MyColoredPoint\color = RGB(255, 0, 0)

Example: Structure copy

  Structure MyPoint
    x.l 
    y.l
  EndStructure

  LeftPoint.MyPoint\x = 10
  LeftPoint\y = 20
  
  RightPoint.MyPoint = LeftPoint
  
  Debug RightPoint\x
  Debug RightPoint\y

Example: Dynamic object

  Structure Person
    Name$
    Age.l
    List Friends$()
  EndStructure

  John.Person
  John\Name$ = "John"
  John\Age   = 23
  
  ; Now, add some friends to John
  ;
  AddElement(John\Friends$())
  John\Friends$() = "Jim"

  AddElement(John\Friends$())
  John\Friends$() = "Monica"
  
  ForEach John\Friends$()
    Debug John\Friends$()
  Next

Example: Static, dynamic array and passing a structure to a procedure

  Structure Whatever
    a.l
    b.l[2]          ; Static array (Standard C) with 2 values b[0] and b[1], not resizable
    Array c.l(3,3)  ; Dynamic array with 16 values c(0,0) to c(3,3), resizable with ReDim()
  EndStructure

  MyVar.Whatever

  Procedure MyProcedure(*blahblah.Whatever)
    *blahblah\a = 5
    *blahblah\b[0] = 1
    *blahblah\b[1] = 2
    *blahblah\c(3,3) = 33
  EndProcedure

  MyProcedure(@MyVar)
  Debug MyVar\a
  Debug MyVar\b[0]
  Debug MyVar\b[1]
  Debug MyVar\c(3,3)
  
  ;Debug MyVar\c(0,10) ; Out-of-bounds index error
  ReDim MyVar\c(3,10)  ; Beware, only the last dimension can be resized!
  Debug  MyVar\c(0,10) ; Cool, the array is bigger now!

Example: Nested structure(s)

  Structure pointF 
    x.f 
    y.f 
  EndStructure 
   
  Structure Field 
    Field1.q 
    Field2.s{6}
    Field3.s
    Array Tab.pointF(3)  
  EndStructure 
 
  Define MyVar.Field 
 
  MyVar\Tab(3)\x = 34.67

Syntax
StructureUnion
  Field1.Type
  Field2.Type
  ...
EndStructureUnion
Description
Structure union are only useful for advanced programmers who want to save some memory by sharing some fields inside the same structure. It's like the 'union' keyword in C/C++.

Note: Each field in the StructureUnion declaration can be of a different type.

Example

  Structure Type
    Name$
    StructureUnion
      Long.l      ; Each field (Long, Float and Byte) resides at the
      Float.f     ; same address in memory.
      Byte.b      ;
    EndStructureUnion
  EndStructure

Example: Extended example (date handling)

  Structure date
    day.s{2}
    pk1.s{1}
    month.s{2}
    pk2.s{1}
    year.s{4}
  EndStructure
  
  Structure date2
    StructureUnion
      s.s{10}
      d.date
    EndStructureUnion
  EndStructure
  
  Dim d1.date2(5)
  
  d1(0)\s = "05.04.2008"
  d1(1)\s = "07.05.2009"
  
  Debug d1(0)\d\day
  Debug d1(0)\d\month
  Debug d1(0)\d\year
  
  Debug d1(1)\d\day
  Debug d1(1)\d\month
  Debug d1(1)\d\year
    
  d2.date2\s = "15.11.2010"
  
  Debug d2\d\day
  Debug d2\d\month
  Debug d2\d\year

Example: Alignment

  Structure Type Align 4
    Byte.b
    Word.w
    Long.l
    Float.f
  EndStructure
  
  Debug OffsetOf(Type\Byte)   ; will print 0
  Debug OffsetOf(Type\Word)   ; will print 4
  Debug OffsetOf(Type\Long)   ; will print 8
  Debug OffsetOf(Type\Float)  ; will print 12

Example: Pointers

  Structure Person
    *Next.Person ; Here the '*' is mandatory to declare a pointer
    Name$
    Age.b
  EndStructure

  Timo.Person\Name$ = "Timo"
  Timo\Age = 25
  
  Fred.Person\Name$ = "Fred"
  Fred\Age = 25
  
  Timo\Next = @Fred ; When using the pointer, the '*' is omitted
  
  Debug Timo\Next\Name$ ; Will print 'Fred'