FreeBasic Union 关键字
最后修改日期:2025 年 6 月 16 日
FreeBasic 的 Union
关键字定义了一种特殊的数据类型,它允许不同的变量共享同一内存空间。Union 对于内存高效的数据表示和类型等同非常有用。
基本定义
FreeBasic 中的 Union
是一种用户自定义数据类型,其中所有成员共享相同的内存地址。Union 的大小等于其最大的成员。
与结构体(structure)不同,结构体的每个成员都有自己的内存空间,而 Union 的成员在内存中是重叠的。写入一个成员会影响所有其他成员,因为它们共享相同的存储空间。
简单的 Union 示例
此示例演示了一个包含整数和浮点数成员的基本 Union。
Union Number As Integer i As Single f End Union Dim num As Number num.i = 65 Print "Integer: "; num.i Print "Float: "; num.f
在这里,我们创建了一个可以存储整数或浮点数的 Union。当我们设置整数值时,浮点数解释会显示相同的内存位,但被解释为浮点数。
包含不同数据类型的 Union
FreeBASIC 中的 Union
允许多个不同类型变量占用相同的内存地址。当您想在同一空间中存储不同种类的数据,但一次只存储一种时,这非常有用。这是一种内存高效的方式来表示重叠的数据格式或重新解释原始字节。
Union Data As Byte b As Integer i As Double d End Union Dim ud As Data ud.d = 3.14159 Print "Byte: "; ud.b Print "Integer: "; ud.i Print "Double: "; ud.d
在此示例中,Data
Union 包含三个成员:一个 Byte
,一个 Integer
,以及一个 Double
。它们都共享相同的内存空间。当我们为 ud.d
赋值时,内存将被填充为双精度浮点数 3.14159
的二进制表示。然后,从 ud.b
或 ud.i
读取会分别将相同的字节解释为 Byte
或 Integer
。
这种技术常用于底层编程,用于类型等同、二进制序列化或解释硬件寄存器等任务。但是,应谨慎使用,因为从最近未写入的 Union 成员读取可能会产生意外的结果。
Union 的大小由其最大的成员决定—在此例中为 Double
,通常占用 8 个字节。所有其他成员都覆盖在同一内存块之上。
用于类型等同的 Union
Union 常用于类型等同—将数据作为不同类型访问。
Union FloatToBytes As Single f As Byte bytes(0 To 3) End Union Dim ftb As FloatToBytes ftb.f = 123.456 For i As Integer = 0 To 3 Print "Byte "; i; ": "; Hex(ftb.bytes(i)) Next
此示例展示了如何检查浮点数的各个字节。Union 允许我们将相同的内存作为浮点数或字节数组访问,从而揭示浮点数的内部表示。
结构体中的 Union
Union 可以嵌入到结构体中,以实现更复杂的数据布局。
Type Variant typeId As Integer Union i As Integer f As Single s As String * 10 End Union End Type Dim v As Variant v.typeId = 1 ' Integer type v.i = 42 Print "Type: "; v.typeId Print "Value: "; v.i
这演示了一个包含 Union 的结构体。Variant
类型可以存储整数、浮点数或字符串。typeId
字段指示当前哪个成员是有效的。这种模式在需要灵活处理多种数据类型的 Datalogic 结构中很常见。
用于硬件访问的 Union
Union 对于访问硬件寄存器或打包数据格式很有用。
Type StatusRegister raw As UShort End Type Function IsReady(sr As StatusRegister) As UShort Return (sr.raw And &b0000000000000001) End Function Function HasError(sr As StatusRegister) As UShort Return (sr.raw And &b0000000000000010) Shr 1 End Function Function IsBusy(sr As StatusRegister) As UShort Return (sr.raw And &b0000000000000100) Shr 2 End Function Dim sr As StatusRegister sr.raw = &h8003 ' Binary: 1000 0000 0000 0011 Print "Raw: "; Hex(sr.raw) Print "Ready: "; IsReady(sr) Print "Error: "; HasError(sr) Print "Busy: "; IsBusy(sr)
此示例模拟了一个硬件状态寄存器。Union 允许我们访问原始值,同时提供解释特定位作为标志的函数。这在直接访问硬件寄存器的底层编程中很常见。
用于网络协议的 Union
Union 可以表示具有不同解释的协议数据单元。
Type OctetArray o As UByte o1 As UByte o2 As UByte o3 As UByte End Type Union IPAddress addr As UInteger octets As OctetArray End Union Dim ip As IPAddress ip.addr = &hC0A80101 ' 192.168.1.1 Print "Dotted: "; ip.octets.o3; "."; ip.octets.o2; "."; ip.octets.o1; "."; ip.octets.o Print "Hex: "; Hex(ip.addr)
按照 o3.o2.o1.o 的顺序打印字节的原因在于计算机如何将多字节值存储在内存中,这是一种称为字节序(endianness)的概念。大多数现代 PC 使用小端格式(little-endian),其中最低有效字节 (o) 存储在最低内存地址,最高有效字节 (o3) 存储在最高内存地址。当 IP 地址存储为 32 位整数时,其字节在内存中从低到高排列。
然而,IP 地址的标准点分十进制表示法(例如 192.168.1.1)要求先出现最高有效字节。因此,为了正确显示地址,我们先打印 o3(最高字节),最后打印 o(最低字节)。这种方法确保输出与人类可读的网络标准格式匹配。需要注意的是,网络协议通常使用大端字节序(网络字节序),因此在不同系统之间传输或接收二进制数据时,您可能需要转换主机字节序和网络字节序,以确保数据的正确解释。
包含数组的 Union
Union 可以包含数组,以实现更灵活的数据访问模式。
Union Matrix As Single values(0 To 15) As Single m(0 To 3, 0 To 3) End Union Dim mat As Matrix ' Fill the matrix For i As Integer = 0 To 15 mat.values(i) = i Next ' Access as 4x4 matrix For y As Integer = 0 To 3 For x As Integer = 0 To 3 Print mat.m(y, x); " "; Next Print Next
此示例显示了一个线性数组和 4x4 矩阵之间的 Union。两种视图访问相同的内存,允许根据算法的需求将数据视为扁平数组或二维矩阵。
本教程介绍了 FreeBasic 的 Union
关键字,并通过实际示例展示了它在不同场景下的用法。