An interesting question came up on the forums the other day about how to mimic “Unions” from C.
Turns out I had answered this some time ago – its close but not exactly the same as in C. But it is close enough to be functional and close enough for most uses.
And it’s not mentioned anywhere in the Xojo docs. Not even in advanced topics.
The requirement was a need to be able to interpret a set of data (4 bytes in the forums post case) in one of two different ways. One was as 4 separate byte values, and the other as 2 16 bit values.
In the example I had given previously the need was a common “record” type that had an identifying “record type” byte as the first byte and several other interpretations of the data that followed. In all cases the records were the same total size but their contents varied.
In the example I have the three structures following :
Structure Structure1
switchCode as uint8
rest(4) as uint8
End Structure
Structure Structure2
switchCode as uint8
val1 as uint16
val2 as uint16
End Structure
Structure Structure3
switchCode as uint8
val1 as uint32
End Structure
Note that each has, in this set up, a byte at the beginning that is at a common offset and that is used to determine which of the three structures is the correct one to be using to interpret the data. In some cases there may be some other indicator or mechanism to know which way to interpret the data.
In this example all structures are defined to be the same total size. This is NOT required. A C union will be the largest of any of the defined union members. So make sure you account for this when you decide what memoryblock size to use for the initial data buffer.
The data buffer is just a memoryblock of whatever size is needed. To interpret the data differently a Ptr is used. And since Ptr’s can interpret the data they point at via a structure we can, once the mb is assigned to the Ptr, now interpret the data using any of our defined structures.
Dim mb As new MemoryBlock(5)
mb.Byte(0) = &h20
mb.UInt16Value(1) = 32
mb.UInt16Value(3) = 254
Dim p As ptr = mb
Dim s1 As structure1 = p.structure1 // makes it so I can read the
// data in mb using the fields from structure1
// but I could use any of the three OR
// some other mechanism to figure out which structure
// to use to inspect the data
Select Case s1.switchcode
Case &h20
Dim s2 As structure2 = p.structure2
// makes it so I can read the data in mb using
// the fields from structure2
Dim value1 As UInt16 = s2.val1
Dim value2 As UInt16 = s2.val2
Break
Case &h21
Dim s3 As structure3 = p.structure3
// makes it so I can read the data in mb using
// the fields from structure3
Dim value1 As UInt32 = s3.val1
Break
Case &h22
Dim struct1 As structure1 = p.structure1
// makes it so I can read the data in mb using
// the fields from structure1
Dim value1 As UInt8 = struct1.rest(0)
Dim value2 As UInt8 = struct1.rest(1)
Dim value3 As UInt8 = struct1.rest(2)
Dim value4 As UInt8 = struct1.rest(3)
Break
End Select
Using this technique we can “overlay” the structure onto the raw data in the memoryblock and read it out using the structures fields.
Very handy especially for those cases where you need to read from file formats, memory formats that involve C unions.