All members of a union will start at the same location in memory, this mean that when you assign a value to a union member you are overwriting partial or totally the rest of the members of the union.
There are 2 common usages of unions. The first is to reuse the same portion of memory to store values of different types at different times. The second usage is to got different interpretations of the same portion of memory.
See the following code:
BEGIN STRUCTURE stWORD
MEMBER BYTE nLoByte
MEMBER BYTE nHiByte
END STRUCTURE
We have defined a structure called stWORD that allow to access the low and high bytes of a 16 bit unsigned integer value
We want to access the low and high words of a 32 bits unsigned value, but also we want to access individual bytes of any of the WORD parts.
BEGIN STRUCTURE stDWORD
BEGIN UNION
MEMBER WORD nLoWord
MEMBER @ stWORD LoWord
END UNION
BEGIN UNION
MEMBER WORD nHiWord
MEMBER @ stWORD HiWord
END UNION
END STRUCTURE
Now we can assign or retrieve values in this way
oDw := stDWORD():New()
oDw:nLoWord := 65535
? oDw:LoWord:nLoByte // 255
But we have a little trouble, we want to access also to our 32 bit value as a single 32 bit integer value. ot4xb not provide direct support for nested unnamed unions, but a small set of commands that allow to do it manually with a high level of flexibility.
BEGIN STRUCTURE stWORD
MEMBER w
GWSTSETOFFSET(0) // Next member will start at the begining of the structure
MEMBER BYTE nLoByte
MEMBER BYTE nHiByte
END STRUCTURE
// --------------------------------------------------------------------------
BEGIN STRUCTURE stDWORD
MEMBER dw
GWSTSETOFFSET(0) // Next member will start at the begining of the structure
MEMBER WORD nLoWord
MEMBER WORD nHiWord
GWSTSETOFFSET(0) // Next member will start at the begining of the structure
MEMBER @ stWORD LoWord
MEMBER @ stWORD HiWord
END STRUCTURE
In the above example have used blocks of the same size, so we was not have the need to take care of the final size of the structure, but with more complex definitions we need to be sure that any previous member surpass the total size of the structure.
BEGIN STRUCTURE stWORD local nMax,nBase
You can include some local declarations to use within your dynamic class function that will hold your structure definition.
nMax := nBase := GWSTGETOFFSET()
Store the current offset as the base and max offset, before add more members
MEMBER w
nMax := Max(GWSTGETOFFSET(),nMax);GWSTSETOFFSET(nBase)
Store the max offset reached by the union members and return to the base
MEMBER BYTE nLoByte
MEMBER BYTE nHiByte
Again check if the maximum offset was reached and adjust the size of the structure to the largest block at the end of the last union level.
nMax := Max(GWSTGETOFFSET(),nMax);GWSTSETOFFSET(nMax)
END STRUCTURE
A common usage of unions with ot4xb is the possibility of view the signed and unsigned representation of the same internal value, for this purpose ot4xb provides a command that go back to the offset previous to the last defined member.
BEGIN STRUCTURE MyStruct
MEMBER LONG sl
GWSTBACK
MEMBER U_INT32 ul
END STRUCTURE
// -----------------------------
o := MyStruct():New()
o:sl := -1
? o:sl // -1
? o:ul // 4294967295