Show/Hide Toolbars

XSharp

NoteThis command is only available in the VO and Vulcan dialects

Purpose

Declare a data structure and its member names.

Syntax

[Modifiers] VOSTRUCT <idStructure> [ALIGN 1|2|4|8]

 MEMBER <idVarList> AS | IS <idType> [, ...]

 MEMBER DIM <ArraySpec> [, ...] AS | IS <idType> [, ...]

[END VOSTRUCT]

 

Note: The MEMBER statement is shown using two syntax diagrams for convenience.  You can declare variables and dimensioned arrays using a single MEMBER statement if each definition is separated by a comma.

Arguments

ModifiersAn optional list of modifiers that specify the visibility or scope of the entity, such as PUBLIC, STATIC, INTERNAL, EXPORT and UNSAFE.

 

<idStructure>A valid identifier name for the structure.  A structure is an entity and shares the same name space as other entities.  This means that it is not possible to have a structure and a constant, for example, with the same name.

 

MEMBERDeclares one or more structure member variables or dimensioned arrays.  You can specify multiple MEMBER declarations on separate lines.

 

<idVarList>A comma-separated list of identifier names for the structure member variables.

 

DIM <ArraySpec>The specification for a dimensioned array to use as a structure member.  <ArraySpec> is one of the following:
<idArray>[<nElements>, <nElements>, <nElements>]
<idArray>[<nElements>][<nElements>][<nElements>]
All dimensions except the first are optional.
 
<idArray> is a valid identifier name for the array to declare.
 
<nElements> defines the number of elements in a particular dimension of an array.  The number of dimensions is determined by how many <nElements> arguments you specify.
 
<nElements> can be a literal numeric representation or a simple numeric expression involving only operators, literals, and DEFINE constants; however, more complicated expressions (such as function calls) are not allowed.

 

AS <idType>Specifies the data type of the variable you are declaring (called strong typing).  For DIM arrays, declares the data type for all array elements.  The AS <idType> is required for all structure members.
 
Refer to the CLASS entry for a list of valid values for <idType>.  Note that the following data types are not supported in structures because they are dynamic types that require garbage collection:
ARRAY
FLOAT        
OBJECT
<idClass>
STRING
USUAL

 

IS <idType>Specifies a structure data type in which the memory needed to hold the structure is allocated on the stack (i.e., <idStructure> is the only <idType> allowed with the IS keyword).

 

ALIGN 1|2|4|8Specifies the memory alignment of the structure. The default alignment is based on the size of the structure members. See the paragraph about alignment below.
You may want to change this when you need to match a C/C++ structure that has been defined with a different alignment (the #pragma pack in a C/C++ header file).
.

Notes

AS vs. IS: Once you have defined a structure, you can use its name to declare variables (see GLOBAL and LOCAL statements in this guide) designed to hold instances of a specific structure.  When you declare a structure variable, you have the choice of using AS or IS typing.  The difference between these two declaration methods is as follows:

       IS automatically allocates the memory needed to hold the structure on the stack and deallocates the memory when the declaring entity returns.

       AS requires that you allocate memory using MemAlloc() when you initialize structure variables.  You must also deallocate the memory used by the structure variable using MemFree() before the declaring entity returns.

 

Important! IS typing is much simpler than AS typing, and in most cases should satisfy your requirements for using structures.  AS typing is recommended for experienced systems programmers who can, for various reasons, object to using the stack in this manner.

 

Allocating substructures: An interesting property of a structure is that it can contain other structures as members but, if you type these substructures using AS, you must allocate and deallocate memory for them.  This is true regardless of whether the containing structure is typed with AS or IS:

 

VOSTRUCT SysOne
  MEMBER iAlpha AS INT
  MEMBER pszName AS PSZ
 
VOSTRUCT SysTwo
  MEMBER iBeta AS INT
  MEMBER strucOne AS SysOne
 
FUNCTION UseStruct()
  LOCAL strucVar AS SysTwo
  strucVar := MemAlloc(_SizeOf(SysTwo))
  strucVar.strucOne := MemAlloc(_SizeOf(SysOne))
  ...
  MemFree(strucVar.strucOne)
  MemFree(strucVar)

 

To simplify your programming, it makes sense to use IS for declaring substructures.  Then, the memory for the substructure will be allocated and deallocated with the memory for its containing structure:

 
VOSTRUCT SysTwo
  MEMBER iBeta   AS INT
  MEMBER strucOne   IS SysOne
 
FUNCTION UseStruct()
  LOCAL strucVar AS SysTwo
  strucVar := MemAlloc(_SizeOf(SysTwo))
  ...
  MemFree(strucVar)

 

Accessing structure members: Structure variables are complex, the components being members that you declare within the structure.  To access a structure member, use the dot operator (.) as follows:

 

<idStructVar>.<idMember>

 

Where <idStructVar> is a variable name or dimensioned array element that you have previously declared using a structure name, and <idMember> is a variable name or dimensioned array element declared within the VOSTRUCT definition as a MEMBER.

 

Examples

This example illustrates IS structure typing. No allocation is necessary but you must pass the structure by reference to calls.

 

VOSTRUCT SysOne     // Define SysOne data structure
  MEMBER iAlpha AS INT
  MEMBER pszName AS PSZ
 
FUNCTION Tester(strucSysOne AS SysOne) AS INT
RETURN strucSysOne.iAlpha
 
FUNCTION UseStruct()
  LOCAL strucVar IS SysOne
  strucVar.iAlpha := 100
  ? Tester(@strucVar)  
  ...

 

This example illustrates AS structure typing. This requires memory allocation and deallocation:

 

VOSTRUCT SysOne     // Define SysOne data structure
  MEMBER iAlpha AS INT
  MEMBER pszName AS PSZ
 
FUNCTION Tester(strucSysOne AS SysOne) AS INT
RETURN strucSysOne.iAlpha
 
FUNCTION UseStruct()
  LOCAL strucVar AS SysOne
  strucVar := MemAlloc(_SizeOf(SysOne))
  strucVar.iAlpha := 100
  ? Tester(strucVar)  
  ...
  MemFree(strucVar)

 

With MEMBER, you can list several groups of variable and array names separated by commas and followed by an AS | IS <idType> clause to indicate that all names listed are to be typed as indicated.  In this example, the variable x and the dimensioned array z are typed as INT, while the variables ptrX and ptrY are typed as PTR.

 

VOSTRUCT SysOne     // Define SysOne data structure
  MEMBER x, DIM z[100] AS INT, ptrX, ptrY AS PTR

 

Default VoStruct Alignment

You can choose to specify an alignment clause in the structure definition or let XSharp determine the best alignment for you.

The default alignment uses the following mechanism:

Each member of a size <= 8 gets a memory address inside the structure that is a multiple of its size. So WORD and SHORT members get aligned on EVEN boundaries, DWORD, LONG, PTR, PSZ members get aligned to 4-byte boundaries and REAL8 members get aligned to 8- byte boundaries. Byte members are not aligned, they can appear everywhere in the structure.

The total size of the structure is aligned to the size of the largest member. This is done to make sure that a dim array of structures (multiple structures adjacent in memory) also align properly

When a structure contains an sub-structure (an IS declaration)  the alignment of the outer structure uses the information from the inner structure.

 

With manual (explicit) alignment each element of the structure is aligned to a memory address that is a multiple of the alignment specified.

 

Some examples of automatic alignment

 

VOSTRUCT test1             // Offset
  MEMBER W AS WORD         // 0
  MEMBER dw AS DWORD       // 4
  MEMBER b AS BYTE         // 8
  // Total size of structure = 12 bytes (largest element = 4, so padded to 12)
  // Memory layout of structure
  // 0123|4567|8901
  // WW..|DWDW|B...
  //
  // WW   = Word
  // DWDW = Dword
  // B    = Byte
  // .    = Padding
 
VOSTRUCT test1             // Offset
  MEMBER W AS WORD         // 0
  MEMBER r8 AS REAL8       // 8
  MEMBER b AS BYTE         // 16
  // Total size of structure = 24 bytes (largest element = 8, so padded to 24)
  // Memory layout of structure
  // 01234567|89012345|67890123
  // WW......|R8R8R8R8|B.......

 

Explicit (manual ) Structure Alignment

In some situations you need to match a structure declaration from a C/C++ header file that has explicit alignment. Then you need to add the ALIGN clause to your structure declaration.

This forces the compiler to align the structure elements to a multiple of the specified size.

An alignment of 1 tells the compiler NOT to use padding but to align all elements of a structure next to eachother. This is the most compact, but may be slower.

 

 

Some examples of explicit alignment

VOSTRUCT test1 ALIGN 1     // Offset
  MEMBER W AS WORD         // 0
  MEMBER r8 AS DWORD       // 2
  MEMBER b AS BYTE         // 6
  // Total size of structure = 7 bytes (multiple of 1)
  // Memory layout of structure
  // 01|2345|6
  // WW|DWDW|B
  //
  // WW   = Word
  // DWDW = Dword
  // B    = Byte
  // .    = Padding
 
VOSTRUCT test1 ALIGN 2     // Offset
  MEMBER W AS WORD         // 0
  MEMBER dw AS DWORD       // 2
  MEMBER b AS BYTE         // 6
  // Total size of structure = 8 bytes ( multiple of 2)
  // Memory layout of structure
  // 01|23|45|67
  // WW|DW|DW|B.
VOSTRUCT test1 ALIGN 4     // Offset
  MEMBER W AS WORD         // 0
  MEMBER r8 AS DWORD       // 4
  MEMBER b AS BYTE         // 8
  // Total size of structure = 12 bytes (multiple of 4)
  // Memory layout of structure
  // 0123|4567|8901
  // WW..|DWDW|B...
 
VOSTRUCT test1 ALIGN 8     // Offset
  MEMBER W AS WORD         // 0
  MEMBER r8 AS DWORD       // 8
  MEMBER b AS BYTE         // 16
  // Total size of structure = 24 bytes (multiple of 8)
  // Memory layout of structure
  // 01234567|89012345|67890123
  // WW......|DWDW....|B.......

See Also

GLOBAL, LOCAL, MemAlloc(), MemFree(),, UNION