C Unions

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

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

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)


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.