Show/Hide Toolbars

XSharp

注意此命令仅用于 VO 和 Vulcan 方言。

用途

声明数据结构及其成员名称。

语法

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

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

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

[END VOSTRUCT]

 

注:为方便起见,MEMBER 语句使用了两个语法。 如果每个定义之间用逗号隔开,则可以使用单个 MEMBER 语句声明变量和标度数组。

参数

Modifiers一个可选的修饰符列表,用于指定主体的可见性或范围,例如:PUBLIC, STATIC, INTERNAL, EXPORT 和 UNSAFE.

 

<idStructure>结构体的有效标识符名称。 结构体是一个实体,与其他实体共享相同的名称空间。 这意味着不可能出现结构和常量同名的情况。

 

MEMBER声明一个或多个结构成员变量或标度数组。 您可以在不同行中指定多个 MEMBER 声明。

 

<idVarList>以逗号分隔的结构成员变量标识符名称列表。

 

DIM <ArraySpec>作为结构成员使用的有维数组的规格。 <ArraySpec> 是以下格式之一:
<idArray>[<nElements>, <nElements>, <nElements>]
<idArray>[<nElements>][<nElements>][<nElements>]
除了第一个维度外,所有维度都是可选的。
 
<idArray> 是要声明的数组的有效标识符名称。
 
<nElements> 定义数组特定维数中的元素个数。 维数由指定 <nElements> 参数的个数决定。
 
<nElements> 可以是字面数字表示或只涉及运算符、字面数字和 DEFINE 常量的简单数字表达式;但不允许使用更复杂的表达式(如函数调用)。

 

AS <idType>指定所声明变量的数据类型(称为强类型)。 对于 DIM 数组,声明所有数组元素的数据类型。 所有结构成员都需要 AS <idType>。
 
有关 <idType> 的有效值列表,请参阅 CLASS 条目。 请注意,结构中不支持以下数据类型,因为它们是需要垃圾回收的动态类型:
ARRAY
FLOAT        
OBJECT
<idClass>
STRING
USUAL

 

IS <idType>指定一种结构体数据类型,在这种数据类型中,保存结构体所需的内存是在堆栈中分配的(也就是说,<idStructure> 是唯一允许使用 IS 关键字的 <idType>)。

 

ALIGN 1|2|4|8指定结构体的内存对齐方式。默认对齐方式基于结构成员的大小。请参见下面关于对齐方式的段落。
当您需要匹配一个定义了不同对齐方式(C/C++ 头文件中的 #pragma pack)的 C/C++ 结构时,可能需要更改对齐方式。
.

备注

AS 与 IS:  一旦定义了结构体,就可以使用结构体的名称来声明变量(参见本指南中的 GLOBAL 和 LOCAL 语句),以保存特定结构体的实例。 在声明结构变量时,可以选择使用 AS 或 IS 类型。 这两种声明方法的区别如下:

       IS 会自动分配在堆栈中存放结构所需的内存,并在声明实体返回时重新分配内存。

       AS 要求在初始化结构变量时使用 MemAlloc() 分配内存。 在声明实体返回之前,还必须使用 MemFree() 注销结构变量使用的内存。

 

重要! IS 类型比 AS 类型简单得多,而且在大多数情况下都能满足使用结构的要求。 AS 类型推荐给有经验的系统程序员,因为他们会因为各种原因反对以这种方式使用堆栈。

 

分配子结构:结构体的一个有趣特性是,它可以包含其他结构体作为成员,但如果使用 AS 键入这些子结构体,就必须为它们分配和取消分配内存。 无论包含的结构是用 AS 还是 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)

为了简化编程,使用 IS 声明子结构是合理的。 然后,子结构的内存将与其包含结构的内存一起分配和清空:

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

访问结构成员:结构变量是一个复杂的变量,由结构中声明的成员组成。 要访问结构成员,请使用点运算符(.),如下所示:

<idStructVar>.<idMember>

其中,<idStructVar> 是先前使用结构名声明的变量名或标度数组元素,<idMember> 是在 VOSTRUCT 定义中作为成员声明的变量名或标度数组元素。

 

示例

本例说明 IS 结构类型。无需分配,但必须通过引用将结构传递给调用。

VOSTRUCT SysOne     // 定义 SysOne 数据结构
  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)  
  ...

本例说明 AS 结构类型。这需要分配和删除内存:

VOSTRUCT SysOne     // 定义 SysOne 数据结构
  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)

使用 MEMBER,可以列出几组变量名和数组名,中间用逗号隔开,后面跟一个 AS | IS <idType> 子句,表示所有列出的变量名和数组名都要按指定的方式键入。 在本例中,变量 x 和数组 z 的类型为 INT,而变量 ptrX 和 ptrY 的类型为 PTR。

VOSTRUCT SysOne     // 定义 SysOne 数据结构
  MEMBER x, DIM z[100] AS INT, ptrX, ptrY AS PTR

 

默认 VoStruct 对齐

您可以选择在结构定义中指定对齐子句,或者让 XSharp 为您确定最佳对齐方式。

默认对齐方式使用以下机制:

每个大小 <= 8 的成员在结构体内部获得的内存地址都是其大小的倍数。因此,WORD 和 SHORT 成员按 EVEN 边界对齐,DWORD、LONG、PTR、PSZ 成员按 4 字节边界对齐,REAL8 成员按 8 字节边界对齐。字节成员不对齐,它们可以出现在结构中的任何地方。

结构的总大小与最大成员的大小对齐。这样做是为了确保结构的 dim 数组(内存中相邻的多个结构)也能正确对齐

当一个结构包含一个子结构(IS 声明)时,外部结构的对齐将使用内部结构的信息。

 

手动(显式)对齐时,结构的每个元素都会对齐到指定对齐倍数的内存地址。

 

自动对齐的一些示例:

VOSTRUCT test1             // Offset
  MEMBER W AS WORD         // 0
  MEMBER dw AS DWORD       // 4
  MEMBER b AS BYTE         // 8
  // 结构总大小 = 12 字节(最大元素 = 4,因此填充为 12)
  // 结构的内存布局
  // 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
  // 结构总大小 = 24 字节(最大元素 = 8,因此填充为 24)
  // 结构的内存布局
  // 01234567|89012345|67890123
  // WW......|R8R8R8R8|B.......

 

显式(手动)结构对齐

在某些情况下,您需要从 C/C++ 头文件中匹配一个具有显式对齐方式的结构声明。这时需要在结构声明中添加 ALIGN 子句。

这将强制编译器将结构元素对齐到指定大小的倍数。

如果对齐值为 1,编译器就不会使用填充,而是将结构中的所有元素紧挨着对齐。这是最紧凑的方法,但速度可能较慢。

 

显示对齐的一些例子

VOSTRUCT test1 ALIGN 1     // Offset
  MEMBER W AS WORD         // 0
  MEMBER r8 AS DWORD       // 2
  MEMBER b AS BYTE         // 6
  // 结构总大小 = 7 字节(1 的倍数)
  // 结构的内存布局
  // 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
  // 结构总大小 = 8 字节(2 的倍数)
  // 结构的内存布局
  // 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
  // 结构总大小 = 12 字节(4 的倍数)
  // 结构的内存布局
  // 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
  // 结构总大小 = 24 字节(8 的倍数)
  // 结构的内存布局
  // 01234567|89012345|67890123
  // WW......|DWDW....|B.......

参见

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