Structures


Syntax
Structure <nom> [Extends <name>] [Align <expression numérique constante>]
  ...
EndStructure 
Description
Structure est utile pour définir un type utilisateur et accéder à des zones mémoires du système d'exploitation par exemple. Les structures peuvent être utilisées pour rendre l'accès à des grands fichiers plus facilement. Cela peut être plus efficace dans la mesure où vous pouvez regrouper dans un même objet des informations communes. On accède aux structures avec le caractère \ . Les structures peuvent s'imbriquer. Les tableaux statiques sont acceptés dans une structure.

Les champs de structure doivent avoir un type explicite parmi tous les Types basiques gérés par PureBasic, à savoir Byte (.b), Ascii (.a), Caractère (.c) , Word (.w) , Unicode (.u), Long (.l), Integer (.i), Float (.f ), Quad (.q), Double (.d)), String (.s) et String Fixe (.s{Longueur}).
Les objets dynamiques tel que les tableaux, listes et maps sont aussi supportés dans les structures et sont automatiquement initialisés quand l'objet utilisant la structure est déclaré. Pour définir un tel champ, utiliser les mot-clés suivant: Array, List et Map.

Généralement, les structures sont utilisées en association avec une variable, un tableau, une liste, ou une map. Toutefois, les utilisateurs avancés pourront allouer une structure en mémoire avec AllocateStructure() et la libérer avec FreeStructure(). Il est aussi possible d'initialiser une structure en mémoire avec InitializeStructure(), de la copier avec CopyStructure(), de la vider avec ClearStructure() et de la reinitialiser avec ResetStructure()

Il est possible de copier une structure complète en utilisant l'opérateur égal ("=") entre deux éléments de même type.

Le paramètre optionnel Extends permet d'étendre une structure existante avec de nouveaux champs. Tous les champs se trouvant dans la structure étendue se retrouveront en tête de la nouvelle structure. C'est très utile pour faire un héritage simple de structures.

Pour les utilisateurs avancés seulement. Le paramètre Align permet d'ajuster l'alignement entre chaque champ de la structure. L'alignement par défaut est de 1, ce qui signifie pas d'alignement. Par exemple, si l'alignement est fixé à 4, chaque champs sera aligné sur 4 octets. Cela peut aider à améliorer les performances lors de l'accès aux champs de la structure, mais cela peut utiliser plus de mémoire, car un certain espace entre chaque champs sera perdu. La valeur spéciale #PB_Structure_AlignC peut être utilisée pour aligner la structure telle qu'elle se ferait en langage C, utile lors de l'importation structures C utilisées avec des fonctions API.
  - SizeOf permet de connaître la taille en octets d'une structure. 
  - OffsetOf donne la position (offset) en mémoire d'un champ d'une structure. 
  

Note : Un Tableau statique dans une structure ne se comporte pas de la même façon qu'un tableau défini avec la commande Dim. Ceci pour être conforme au format de structures en C/C++ (pour permettre un portage direct des structures de l'API). Ce qui signifie que a[2] assignera un tableau de 0 à 1 (deux éléments) alors que Dim a(2) assignera un tableau de 0 à 2 (trois éléments). Et Les fonctions de la bibliothèque Array ne peuvent pas être utilisées avec ce type de tableaux.

Lorsque vous utilisez des pointeurs dans les structures, L'étoile '*' doit être omise lors de l'utilisation du champ, une fois de plus pour faciliter le portage de code API. Cela peut être considéré comme une bizarrerie (et pour être honnête, ça l'est) mais c'est comme ça depuis le début de PureBasic et beaucoup, beaucoup de sources sont écrites de cette façon et cela restera inchangé.

Quand beaucoup de champs doivent être remplis en une fois, il est conseillé d'utiliser With : EndWith pour réduire la quantité de code à saisir et améliorer sa lisibilité.

Exemple

  Structure Personne
    Nom.s
    Prenom.s 
    Age.w 
  EndStructure

  Dim MesAmis.Personne(100)

  ; Ici la position '0' du tableau MesAmis()
  ; contiendra une personne et ses informations personnelles

  MesAmis(0)\Nom = "Durand"
  MesAmis(0)\Prenom = "Michel" 
  MesAmis(0)\Age = 32

Exemple: Structure plus complexe (Tableau statique imbriqué)

   Structure Fenetre
    *FenetreSuivante.Fenetre  ; Pointe vers un autre objet fenêtre
    x.w 
    y.w
    Nom.s[10]  ; 10 noms possibles
  EndStructure

Exemple: Structure étendue

  Structure MonPoint
    x.l 
    y.l
  EndStructure

  Structure MonPointEnCouleur Extends MonPoint
    couleur.l 
  EndStructure

  ColoredPoint.MonPointEnCouleur\x = 10
  ColoredPoint.MonPointEnCouleur\y = 20
  ColoredPoint.MonPointEnCouleur\couleur = RGB(255, 0, 0)

Exemple: Copie de structure

  Structure MonPoint
    x.l 
    y.l
  EndStructure

  PointGauche.MonPoint\x = 10
  PointGauche\y = 20
  
  PointDroit.MonPoint = PointGauche
  
  Debug PointDroit\x
  Debug PointDroit\y

Exemple: Objet Dynamique

  Structure Personne
    Nom$
    Age.l
    List Amis$()
  EndStructure

  Jean.Personne
  Jean\Nom$ = "Jean"
  Jean\Age   = 23
  
  ; Ajoutons des amis à Jean
  ;
  AddElement(Jean\Amis$())
  Jean\Amis$() = "Jim"

  AddElement(Jean\Amis$())
  Jean\Amis$() = "Monica"
  
  ForEach Jean\Amis$()
    Debug Jean\Amis$()
  Next

Exemple: Tableau statique, dynamique et Structure en argument de procédure

  Structure Truc
    a.l
    b.l[2]          ; Tableau statique (Standard C) avec 2 valeurs b[0] et b[1], non redimensionnable
    Array c.l(3,3)  ; Tableau dynamique avec 16 valeurs de c(0,0) à c(3,3), redimensionnable avec ReDim()
  EndStructure

  MaVar.Truc

  Procedure MaProcedure(*blabla.Truc)
    *blabla\a = 5
    *blabla\b[0] = 1
    *blabla\b[1] = 2
    *blabla\c(3,3) = 33
  EndProcedure

  MaProcedure(@MaVar)
  Debug MaVar\a
  Debug MaVar\b[0]
  Debug MaVar\b[1]
  Debug MaVar\c(3,3)
  
  ;Debug MaVar\c(0,10) ; Erreur index hors limite
  ReDim MaVar\c(3,10)  ; Attention, seule la dernière dimension peut être redimensionnée !
  Debug  MaVar\c(0,10)

Exemple: Structure de structure(s)

  Structure pointF 
    x.f 
    y.f 
  EndStructure 
   
  Structure Champs 
    Champs1.q 
    Champs2.s{6}
    Champs3.s
    Array Tab.pointF(3)  
  EndStructure 
 
  Define MaVar.Champs 
 
  MaVar\Tab(3)\x = 34.67

Exemple: Alignement Mémoire

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

Exemple: Pointers

  Structure Personne
    *Next.Personne ; Ici, le '*' est obligatoire pour déclarer un pointeur
    Nom$
    Age.b
  EndStructure

  Timo.Personne\Nom$ = "Timo"
  Timo\Age = 25
  
  Fred.Personne\Nom$ = "Fred"
  Fred\Age = 25
  
  Timo\Next = @Fred ; Lorsque vous utilisez le pointeur, le '*' est omis
  
  Debug Timo\Next\Nom$ ; Affichera 'Fred'



Syntax
StructureUnion
  Champs.Type
  Champs.Type
  ...
EndStructureUnion
Description
StructureUnion est prévu pour les programmeurs avancés qui souhaitent économiser de la mémoire en partageant certains champs à l'intérieur d'une même structure. Il s'agit d'un équivalent du mot clef 'union' en C/C++.

Note: Chaque champ dans la déclaration StructureUnion peut être d'un type différent.
Note: Chaque champ dans la déclaration StructureUnion est placé à la même adresse mémoire.

Exemple

  Structure Type
    Nom$
    StructureUnion
      Long.l      ; Chaque champ (Long, Float et Byte) est placé à la même adresse mémoire.
      Float.f     ; 
      String.b    ; 
    EndStructureUnion    
  EndStructure 

Exemple: Exemple RVB

  Structure StrCouleur
    Rouge.a
    Vert.a
    Bleu.a
    Alpha.a
  EndStructure

  Structure StrCouleurU
    StructureUnion
      Composant.StrCouleur
      Couleur.l
      Octet.a[4]
    EndStructureUnion
  EndStructure

  Define Couleur1.StrCouleurU

  Couleur1\Couleur = RGBA($10, $20, $30, $FF)
  Debug "hex = " + Hex(Couleur1\Couleur, #PB_Long)    ;hex = FF302010 (processeurs little-endian)
  Debug "r = "   + Hex(Couleur1\Composant\Rouge)      ;r = 10
  Debug "v = "   + Hex(Couleur1\Composant\Vert)       ;v = 20
  Debug "b = "   + Hex(Couleur1\Composant\Bleu)       ;b = 30
  Debug "a = "   + Hex(Couleur1\Composant\Alpha)      ;a = FF

  Debug "Octet0 = " + Hex(Couleur1\Octet[0])          ;Octet0 = 10
  Debug "Octet1 = " + Hex(Couleur1\Octet[1])          ;Octet1 = 20
  Debug "Octet2 = " + Hex(Couleur1\Octet[2])          ;Octet2 = 30
  Debug "Octet3 = " + Hex(Couleur1\Octet[3])          ;Octet3 = FF

Exemple: Exemple gestion de dates

  Structure StrDate ;jj.mm.aaa
    jour.s{2}
    separateur1.s{1}
    mois.s{2}
    separateur2.s{1}
    an.s{4}
  EndStructure

  Structure StrDateU
    StructureUnion
      s.s{10}
      d.StrDate
    EndStructureUnion
  EndStructure

  ;Un tableau
  Dim MaDate.StrDateU(365)
  MaDate(0)\s = "05.04.2028"

  Debug MaDate(0)\d\jour    ; 05
  Debug MaDate(0)\d\mois    ; 04
  Debug MaDate(0)\d\an      ; 2028
  Debug MaDate(0)\s         ; 05.04.2028

  ;Une variable
  MaDate2.StrDateU\s = "15.11.2030"

  Debug MaDate2\d\jour      ; 15
  Debug MaDate2\d\mois      ; 11
  Debug MaDate2\d\an        ; 2030
  Debug MaDate2\s           ; 15.11.2030