结构中的每个字段都有相对于结构第一个字节的偏移量,而联合 (union) 中所有的字段则都起始于同一个偏移量。一个联合的存储大小即为其最大字段的长度。如果不是结构的组成部分,那么需要用 UNION 和 ENDS 伪指令来定义联合:
unionname UNION
union-fields
unionname ENDS
如果联合嵌套在结构内,其语法会有一点不同:
structname STRUCT
structure-fields
UNION unionname
union-fields
ENDS
structname ENDS
除了其每个字段都只有一个初始值之外,联合字段声明的规则与结构的规则相同。例如,Integer 联合对同一个数据声明了 3 种不同的大小属性,并将所有的字段都初始化为 0:
Integei; UNION
D DWORD 0
W WORD 0
B BYTE 0
Integer ENDS
一致性
如果使用初始值,那么它们必须为相同的数值。假设 Integer 声明了 3 个不同的初始值:
Integer UNION
D DWORD 1
W WORD 5
B BYTE 8
Integer ENDS
同时还假设声明了一个 Integer 变量 mylnt 使用默认初始值:
.data
mylnt Integer <>
结果发现,myInt.D、myInt.W 和 myInt.B 都等于 1。字段 W 和 B 中声明的初始值会被汇编器忽略。
结构包含联合
在结构声明中使用联合的名称,就可以使联合嵌套在这个结构中。方法如同下面在 Fileinfo 结构中声明 FilelD 字段一样:
Fileinfo STRUCT
FilelD Integer <>
FileName BYTE 64 DUP(?)
Fileinfo ENDS
还可以直接在结构中定义联合,方法如同下面定义 FilelD 字段一样:
Fileinfo STRUCT
UNION FilelD
D DWORD ?
W WORD ?
B BYTE ?
ENDS
FileName BYTE 64 DUP(?)
Fileinfo ENDS
声明和使用联合变量
联合变量的声明和初始化方法与结构变量相同,只除了一个重要的差异:不允许初始值多于一个。下面是 Integer 类型变量的例子:
val1 Integer <12345678h>
val2 Integer <100h>
val3 Integer <>
在可执行指令中使用联合变量时,必须给出字段的一个名称。下面的例子把寄存器的值赋给了 Integer 联合字段。注意其可以使用不同操作数大小的灵活性:
mov val3.B, al
mov val3.W, ax
mov val3.D, eax
联合还可以包含结构。有些 MS-Windows 控制台输入函数会使用如下 INPUT_RECORD 结构,它包含了一个名为 Event 的联合,这个联合对几个预定义的结构类型进行选择。EventType 字段表示联合中出现的是哪种 record。每一种结构都有不同的布局和大小,但是一次只能使用一种:
INPUT_RECORD STRUCT
EventType WORD ?
ALIGN DWORD
UNION Event
KEY_EVENT_RECORD <>
MOUSE_EVENT_RECORD <>
WINDOW_BUFFER_SIZE_RECORD <>
MENU_EVENT_RECORD <>
FOCUS_EVENT_RECORD <>
ENDS
INPUT_RECORD ENDS
Win32 API
在命名结构时,常常使用单词 RECORD。KEY_EVENT_RECORD 结构的定义如下所示:
KEY_EVENT_RECORD STRUCT
bKeyDown DWORD ?
wRepeatCount WORD ?
wVirtualKeyCode WORD ? wVirtualScanCode WORD ?
UNION uChar
UnicodeChar WORD ?
AsciiChar BYTE ?
ENDS
dwControlKeyState DWORD ?
KEY_EVENT_RECORD ENDS