Union provides a way to circumvent the type system of C and allow multiple types to reference an object. The syntax of Joint Declaration is the same as that of struct, but the semantics is quite different. Instead of referencing different memory blocks with different domains, they reference the same block.
Here are some examples:
Struct stest
{
Char C;
Int I [2];
Double var;
};
Union Utest
{
Char C;
Int I [2];
Double var;
};
We can view the distribution in the memory:
Type c I var size
Stest 0 4 12 20
Utest 0 0 0 8
The data above indicates the memory block offset from the first address. If we define Utest * pu, we can view p-> C; P-> I [0]; P-> var; respectively. They all reference the starting position of the data structure. Of course, if sizeof is used. The size of Utest is the size of its largest data member.
Union is of much use. Here is how to use it to save space:
Suppose we have a binary tree data structure. Each leaf node has a double data value, and each internal node has a pointer to the child node, but there is no data (because it is a leaf node ). If we declare:
Struct Node
{
Struct node * pleft;
Struct node * pright;
Double data;
};
We can know that such a struct requires 16 bytes, and each leaf node will waste half of the bytes. On the contrary, if we declare a node using a union:
Union Node
{
Struct
{
Union node * pleft;
Union node * pright;
} Inter;
Double data;
};
In this way, each node only needs 8 bytes. If pnode is a pointer to the Union node type, we use pnode-> data to reference the data of the leaf node. Pnode-> inter. pleft and pnode-> inter. pright reference the children of internal nodes.
In this case, you may be unable to determine the node (internal node or leaf node ). We can reference a flag domain.
Struct Node
{
Bool isleaf;
Union
{
Struct
{
Union node * pleft;
Union node * pright;
} Inter;
Double data;
} Info;
}
However, this small savings may lead to lower code readability. The benefits of joint operations can be ignored here. For data structures in multiple domains, this saving will be more attractive.
Another usage is to access bits of different data types. For example:
Uint floattobits (float fvar)
{
Union
{
Float FV;
Uint UI;
} Temp;
Temp. FV = fvar;
Return temp. UI;
}
Let's look at the assembly code:
MoV eax, dword ptr [fvar]
MoV dword ptr [temp], eax
It is the same as the Code returned by the following function:
Uint floattobits (uint var)
{
Return var;
}
This proves that there is no information in the assembly code. No matter what type it is, it is a fixed value offset from EBP. The process is a simple copy, and no bit is modified.
Let's take another example:
Double bittodouble (uint uparam1, uint uparam2)
{
Union
{
Double D;
Uint U [2];
} Temp;
Temp. U [0] = uparam1;
Temp. U [1] = uparam2;
Return temp. D;
}
Now, let's take a look at more usage. Here we will introduce you --
Union provides a way to circumvent the type system of C and allow multiple types to reference an object. The syntax of Joint Declaration is the same as that of struct, but the semantics is quite different. Instead of referencing different memory blocks with different domains, they reference the same block.
Here are some examples:
Struct stest
{
Char C;
Int I [2];
Double var;
};
Union Utest
{
Char C;
Int I [2];
Double var;
};
We can view the distribution in the memory:
Type c I var size
Stest 0 4 12 20
Utest 0 0 0 8
The data above indicates the memory block offset from the first address. If we define Utest * pu, we can view p-> C; P-> I [0]; P-> var; respectively. They all reference the starting position of the data structure. Of course, if sizeof is used. The size of Utest is the size of its largest data member.
Union is of much use. Here is how to use it to save space:
Suppose we have a binary tree data structure. Each leaf node has a double data value, and each internal node has a pointer to the child node, but there is no data (because it is a leaf node ). If we declare:
Struct Node
{
Struct node * pleft;
Struct node * pright;
Double data;
};
We can know that such a struct requires 16 bytes, and each leaf node will waste half of the bytes. On the contrary, if we declare a node using a union:
Union Node
{
Struct
{
Union node * pleft;
Union node * pright;
} Inter;
Double data;
};
In this way, each node only needs 8 bytes. If pnode is a pointer to the Union node type, we use pnode-> data to reference the data of the leaf node. Pnode-> inter. pleft and pnode-> inter. pright reference the children of internal nodes.
In this case, you may be unable to determine the node (internal node or leaf node ). We can reference a flag domain.
Struct Node
{
Bool isleaf;
Union
{
Struct
{
Union node * pleft;
Union node * pright;
} Inter;
Double data;
} Info;
}
However, this small savings may lead to lower code readability. The benefits of joint operations can be ignored here. For data structures in multiple domains, this saving will be more attractive.
Another usage is to access bits of different data types. For example:
Uint floattobits (float fvar)
{
Union
{
Float FV;
Uint UI;
} Temp;
Temp. FV = fvar;
Return temp. UI;
}
Let's look at the assembly code:
MoV eax, dword ptr [fvar]
MoV dword ptr [temp], eax
It is the same as the Code returned by the following function:
Uint floattobits (uint var)
{
Return var;
}
This proves that there is no information in the assembly code. No matter what type it is, it is a fixed value offset from EBP. The process is a simple copy, and no bit is modified.
Let's take another example:
Double bittodouble (uint uparam1, uint uparam2)
{
Union
{
Double D;
Uint U [2];
} Temp;
Temp. U [0] = uparam1;
Temp. U [1] = uparam2;
Return temp. D;
}
Now, let's take a look at more usage. Here we will introduce you --