For example,
union
{
float fl,
unsigned int uinteg,
char ch,
int integ
} foo;
All this is stored mixed in one area of memory. What’s the point, because once you set the values
foo.fl = 3.14f;
foo.uinteg = 666;
foo.ch = 'a';
foo.int = -25;
will not be able to get them back – will everything get mixed up? A way to save a couple of bytes or a couple of clock cycles and still keep readability? Not writing 4 different functions, but writing one that accepts a union
and in it you already decide what to do? In this case, wouldn’t it be easier to accept void *
and then cast to the type you need? As an example of “Just cast” I will give the following code:
Classic example:
typedef enum {STR, INT} tType;
typedef struct {
tType typ; // typ is separate.
union {
int ival; // ival and sval occupy same memory.
char * sval;
};
} tVal;
void printer (tVal uni)
{
if (uni.type == INTEGER) // blah-blah
uni.ival // Use integer
else
ini.sval // Otherwise
}
The printer function can be rewritten like this:
void printer (void * data, tType typ)
{
if (tType == INTEGER)
{
(int *) data // Do something
}
}
Another example:
union
{
int a;
int b;
int c;
} bar;
bar.a = 20;
bar.b = 50; // Lost a value :(
Again, what’s the point if I can first create a separate variable int a = 20;
and then change its value a = 50;
and the effect is exactly the same right? Looks like powerful sorcery.
Answer 1, authority 100%
Union -s (unions) are used in two cases:
-
To create a “generic” data type capable of storing not a single, but one of the predefined types. To do this, an integer field is added to the union indicating the type of data currently stored:
struct variant { union tag_value { int intValue; float floatValue } value; unsigned storedType; };
One example of this in real life is the structure
VARIANT
from Windows API.In other words, it is the predecessor of modern
boost :: variant
,QVariant
, etc. However, the above classes can store non-primitive types (with constructors, destructors and operators copy), butunion
is not. -
To convert between incompatible types. Traditionally, the conversion operator
(T)
orreinterpret_cast & lt; & gt;
is used for this purpose. However, these methods are dangerous by violating strict aliasing rule and, as a result, generating an undefined (that is, unpredictable) behavior.Correct conversion methods are either
memcpy
(a similar call to which is thrown by the compiler), or usingunion
.UPD: Attention! Conversion via
union
is valid only in C , but not in C++. In the answer to the question “Accessing inactive union member and undefined behavior?” references are made to the following clauses of the standards:-
C++ 11 (no explicit permission for type punning)
9.5 [class.union]
Only one non-static field can be active in a union at a time; therefore, there can be no more than one value in the union at any given time.
9.5 Unions [class.union]
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time.
-
Answer 2, authority 28%
One practical way to use a union
is to access the bits of the information being passed. Let’s say information is transmitted bit by bit at a time 32 bits.
struct _info_s
{
uint32_t info_a: 2;
uint32_t info_b: 10;
uint32_t info_c: 8;
uint32_t info_d: 5;
uint32_t info_e: 5;
uint32_t info_f: 2;
} __ atributte __ ((packed));
typedef struct _info_s info_s;
union _total_u
{
uint32_t array;
info_s info;
};
When reading / writing, we can immediately operate on uint32_t
, but access to bits appears immediately.
Answer 3, authority 24%
Here’s what Björn Stroustrup answered a similar question to me at one time:
Unions are used when you want to save space by reusing space for
information one type at a time. I don’t use them much.
In other words, in our time they are generally not needed.
Answer 4, authority 10%
If I understand correctly, this is a combination of variables in memory. Sometimes och is convenient if you want to see a variable in a different light or you want to access only part of the variable …
For example, String can be interpreted as byte [] array or byte [] [2] rectangular array, and integer can be decomposed into byte_lo and byte_hi
Answer 5
union is a very useful thing when working with microcontrollers when it is necessary to process data arriving in a “raw” form (for example, when transferring over a CAN network or ethernet).
For example, when transmitting over an information network, two types of messages are possible:
typedef struct {
char id;
unsigned int code1;
unsigned int code2;
} Msg1;
typedef struct {
char id;
char code_error;
} Msg2;
Create a union
union {
char data [maxLen];
Msg1 msg1;
Msg2 msg2;
} DATA;
Create a variable
DATA data;
We write the received data into the data.data
variable, and interpret the data in messages using the values data.msg1
or data.msg2
.
You can also do without union by directly converting to point to “raw” data into a pointer of one of the types of messages and work with message fields, but when you enable optimization (for example -O2 or -O3), this code stops working. It is necessary to add the volatile
keyword everywhere when declaring variables.
Answer 6
As already described, union is very useful when working with microcontrollers, for example, to save memory, you can declare a structure of flags (or values), bind the size in bits and add a variable comparable to the desired bit size.
typedef union {
struct {
bool flag1: 1;
bool flag2: 1;
bool flag3: 1;
bool flag4: 1;
bool flag5: 1;
uint8_t param: 3;
}; // total 8 bits
uint8_t flags; // variable of the same size or larger
} FLAGS;