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.