[ACCEPTED]-Examples of Union in C-unions
One classic is to represent a value of "unknown" type, as 15 in the core of a simplistic virtual machine:
typedef enum { INTEGER, STRING, REAL, POINTER } Type;
typedef struct
{
Type type;
union {
int integer;
char *string;
float real;
void *pointer;
} x;
} Value;
Using 14 this you can write code that handles "values" without 13 knowing their exact type, for instance implement 12 a stack and so on.
Since this is in (old, pre-C11) C, the 11 inner union must be given a field name in 10 the outer struct
. In C++ you can let the union
be anonymous. Picking 9 this name can be hard. I tend to go with 8 something single-lettered, since it is almost 7 never referenced in isolation and thus it 6 is always clear from context what is going 5 on.
Code to set a value to an integer might 4 look like this:
Value value_new_integer(int v)
{
Value v;
v.type = INTEGER;
v.x.integer = v;
return v;
}
Here I use the fact that 3 struct
s can be returned directly, and treated 2 almost like values of a primitive type (you 1 can assign struct
s).
Here's a little one I use every day:
struct tagVARIANT {
union {
struct __tagVARIANT {
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union {
LONG lVal; /* VT_I4 */
BYTE bVal; /* VT_UI1 */
SHORT iVal; /* VT_I2 */
FLOAT fltVal; /* VT_R4 */
DOUBLE dblVal; /* VT_R8 */
VARIANT_BOOL boolVal; /* VT_BOOL */
_VARIANT_BOOL bool; /* (obsolete) */
SCODE scode; /* VT_ERROR */
CY cyVal; /* VT_CY */
DATE date; /* VT_DATE */
BSTR bstrVal; /* VT_BSTR */
IUnknown * punkVal; /* VT_UNKNOWN */
IDispatch * pdispVal; /* VT_DISPATCH */
SAFEARRAY * parray; /* VT_ARRAY */
BYTE * pbVal; /* VT_BYREF|VT_UI1 */
SHORT * piVal; /* VT_BYREF|VT_I2 */
LONG * plVal; /* VT_BYREF|VT_I4 */
FLOAT * pfltVal; /* VT_BYREF|VT_R4 */
DOUBLE * pdblVal; /* VT_BYREF|VT_R8 */
VARIANT_BOOL *pboolVal; /* VT_BYREF|VT_BOOL */
SCODE * pscode; /* VT_BYREF|VT_ERROR */
CY * pcyVal; /* VT_BYREF|VT_CY */
DATE * pdate; /* VT_BYREF|VT_DATE */
BSTR * pbstrVal; /* VT_BYREF|VT_BSTR */
IUnknown ** ppunkVal; /* VT_BYREF|VT_UNKNOWN */
IDispatch ** ppdispVal; /* VT_BYREF|VT_DISPATCH */
SAFEARRAY ** pparray; /* VT_BYREF|VT_ARRAY */
VARIANT * pvarVal; /* VT_BYREF|VT_VARIANT */
PVOID byref; /* Generic ByRef */
CHAR cVal; /* VT_I1 */
USHORT uiVal; /* VT_UI2 */
ULONG ulVal; /* VT_UI4 */
INT intVal; /* VT_INT */
UINT uintVal; /* VT_UINT */
DECIMAL * pdecVal; /* VT_BYREF|VT_DECIMAL */
CHAR * pcVal; /* VT_BYREF|VT_I1 */
USHORT * puiVal; /* VT_BYREF|VT_UI2 */
ULONG * pulVal; /* VT_BYREF|VT_UI4 */
INT * pintVal; /* VT_BYREF|VT_INT */
UINT * puintVal; /* VT_BYREF|VT_UINT */
} __VARIANT_NAME_3;
} __VARIANT_NAME_2;
DECIMAL decVal;
} __VARIANT_NAME_1;
};
This 23 is the definition of the OLE automation 22 variant data type. As you can see it has 21 lots of possible types. There are lots of 20 rules around the types you can use in different 19 situations, depending on the capabilities 18 of your intended client code. Not all types 17 are supported by all languages.
The types 16 with VT_BYREF
after them are used by languages such 15 as VBScript that pass parameters by reference 14 by default. This means if you have some 13 code that cares about the variant structure 12 details (such as C++) being called by code 11 that doesn't (such as VB), then you have 10 to carefully dereference the variant parameter 9 if required.
The byref types are also used 8 to return values from functions. There is 7 also support for array types using the weirdly 6 misnamed SAFEARRAY
type - so difficult to use from 5 C++.
If you have an array of strings, you 4 can pass it to vbscript, but it cannot be 3 used (except to print the size). To actually 2 read the values, the array data needs to 1 be of type VT_BYREF | VT_BSTR
.
Unions are also commonly used in the lexical 17 analysis and parsing stage of language processors, like 16 compilers and interpreters. Here is one 15 I'm editing right now.
union {
char c;
int i;
string *s;
double d;
Expression *e;
ExpressionList *el;
fpos_t fp;
}
The union is used 14 to associate semantic values with the tokens 13 of the lexical analyzer and the productions 12 of the parser. This practice is quite common 11 in grammar generators, like yacc, which provides 10 explicit support for it. The union can 9 hold any of its values, but only one of 8 them at the time. For instance, at any 7 one point from the input file you've either 6 read a character constant (stored in c
), or 5 an integer (stored in i
) or a floating point 4 number (stored in d
). The grammar generator 3 provides considerable assistance for determining 2 which of the values is stored at any one 1 time depending on the rule being processed.
Please avoid "hacks" with union, they cause 8 portability headaches (endianness, alignment 7 issues).
A legitimate use of union is to 6 store different data types at the same place, preferably 5 with a tag so that you know which type it 4 is. See the example by 1800 INFORMATION.
Don't 3 use union to convert between data types, e.g. from 2 an integer to several bytes. Use shift and 1 masking instead for portability.
We use unions for packed messages at work 10 (C/C++), so we can pass around a structure 9 with a union as a data member, then access 8 the correct path based on id field in the 7 structure.
Worked fine until somebody wrote 6 the structure to a file, now we are limited 5 to the largest data used in the file, because 4 even though there's a file version, nobody 3 ever changed it....
So while useful for in-memory 2 work, avoid blindly writing them to disk 1 or network.
Coincidentally, I just used one in a Stackoverflow 9 answer here so I could treat a word that was 8 made up of 6 bit fields as two 16 bit unsigned 7 integers.
Years ago, I also used one for 6 (the first) ARM C compiler - the instructions 5 in those days were all 32 bit, but had different 4 layouts depending on the exact instruction. So 3 I had a union to represent an ARM instruction, containing 2 a set of structs which each had the appropriate 1 bitfields for a specific instruction type.
struct InputEvent
{
enum EventType
{
EventKeyPressed,
EventKeyPressRepeated,
EventKeyReleased,
EventMousePressed,
EventMouseMoved,
EventMouseReleased
} Type;
union
{
unsigned int KeyCode;
struct
{
int x;
int y;
unsigned int ButtonCode;
};
};
};
...
std::vector<InputEvent> InputQueue;
with the union hack I can simply make a 2 vector of objects. I'm sure this could be 1 made more clean...but it works for me - KISS
#define DWORD unsigned int
#define WORD unsigned short
#define BYTE unsigned char
typedef union _DWORD_PART_ {
DWORD dwWord;
struct {
WORD dwMSB;
WORD dwLSB;
}hw;
struct {
BYTE byMSB;
BYTE byMSBL;
BYTE byLSBH;
BYTE byLSB;
} b;
} DWORD_PART;
This is an easy way to access the words 3 parts. (An once you are done, any change 2 in endianness of the platform can also be 1 handled easily)
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.