ZetCode

FreeBasic Union Keyword

last modified June 16, 2025

The FreeBasic Union keyword defines a special data type that allows different variables to share the same memory space. Unions are useful for memory-efficient data representation and type punning.

Basic Definition

A Union in FreeBasic is a user-defined data type where all members share the same memory location. The size of a union is equal to its largest member.

Unlike structures, where each member has its own memory space, union members overlap in memory. Writing to one member affects all others since they share the same storage.

Simple Union Example

This example demonstrates a basic union with integer and float members.

simple_union.bas
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

Here we create a union that can hold either an integer or a float. When we set the integer value, the float interpretation shows the same memory bits interpreted as a floating-point number.

Union with Different Data Types

A Union in FreeBASIC allows multiple variables of different types to occupy the same memory location. This is useful when you want to store different kinds of data in the same space, but only one at a time. It's a memory-efficient way to represent overlapping data formats or reinterpret raw bytes.

mixed_union.bas
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

In this example, the Data union contains three members: a Byte, an Integer, and a Double. All of them share the same memory space. When we assign a value to ud.d, the memory is filled with the binary representation of the double-precision floating-point number 3.14159. Reading from ud.b or ud.i then interprets those same bytes as a Byte or Integer, respectively.

This technique is often used in low-level programming for tasks like type punning, binary serialization, or interpreting hardware registers. However, it should be used with care, as reading from a union member that wasn't most recently written can produce unexpected results.

The size of a union is determined by its largest member—in this case, Double, which typically occupies 8 bytes. All other members are overlaid on top of that same memory block.

Union for Type Punning

Unions are often used for type punning - accessing data as a different type.

type_punning.bas
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

This example shows how to examine the individual bytes of a floating-point number. The union allows us to access the same memory as either a float or an array of bytes, revealing the internal representation of the float.

Union in Structures

Unions can be embedded within structures for more complex data layouts.

union_in_struct.bas
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

This demonstrates a structure containing a union. The Variant type can hold either an integer, a float, or a string. The typeId field indicates which member is currently valid. This pattern is common in data structures that need to handle multiple types of data flexibly.

Union for Hardware Access

Unions are useful for accessing hardware registers or packed data formats.

hardware_union.bas
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)

This example models a hardware status register. The union allows us to access the raw value while providing functions to interpret specific bits as flags. This is common in low-level programming where hardware registers are accessed directly.

Union for Network Protocols

Unions can represent protocol data units with different interpretations.

network_union.bas
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)

The reason for printing the bytes in the order o3.o2.o1.o is rooted in how computers store multi-byte values in memory, a concept known as endianness. Most modern PCs use little-endian format, where the least significant byte (o) is stored at the lowest memory address and the most significant byte (o3) at the highest. When an IP address is stored as a 32-bit integer, its bytes are arranged in memory from least to most significant.

However, the standard dotted-decimal notation for IP addresses (e.g., 192.168.1.1) expects the most significant byte first. Therefore, to display the address correctly, we print o3 (the highest-order byte) first and o (the lowest-order byte) last. This approach ensures that the output matches the human-readable and network-standard format. It's important to note that network protocols typically use big-endian (network byte order), so when transmitting or receiving binary data across different systems, you may need to convert between host and network byte order to ensure correct interpretation of the data.

Union with Arrays

Unions can contain arrays for more flexible data access patterns.

array_union.bas
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

This example shows a union between a linear array and a 4x4 matrix. Both views access the same memory, allowing the data to be treated either as a flat array or a two-dimensional matrix depending on the needs of the algorithm.

This tutorial covered the FreeBasic Union keyword with practical examples showing its usage in different scenarios.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all FreeBasic Tutorials.