What are unions?
A union
functions as a block of memory that is used to store variables of different types so that when a new value is assigned to any of the fields, the existing information is overwritten with the new value. That is, the fields share the same space in memory, or part of it (if the field is less than the total space of the union).
Thus, all fields of union
start at the same memory address. That way you can go get pieces of the whole at a time and go write them in the file as you did.
Unions vs Structs
I know this is not part of your question, but just for comparison purposes, this operation differs from struct
's, where each field has its memory address apart, its memory space. That is, in struct
's, each field has its value and when assigning a value to one field, does not change the value of another. In union
's fields have the same start address.
About your example
Leaving the quirks a little aside for didactic issues, an integer (int) in c / c ++ usually occupies 4 bytes (32 bits) of memory (with a 32-bit processor). So in your example, in fact, it is not the 'half' that is being printed first, but the first byte of int
, because type char
occupies 1 byte. So in the example you wrote the first two bytes of int
.
Simple union example
Here you can see how union
's can be used to' pick up pieces' of an integer or other type of information:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// O tamanho que a union armazena na memória é o tamanho do maior campo da union
union MinhaUnion {
uint32_t x; // ocupa 4 bytes de memória
uint16_t y; // ocupa 2 bytes de memória
uint8_t z; // ocupa 1 byte de memória
}; // tamanho total que a union ocupa na memória é 4 bytes.
int main() {
MinhaUnion u;
// coloca o inteiro nos 4 bytes da union
u.x = 123456789;
// pega o inteiro total, depois o valor inteiro dos dois primeiros bytes, depois o inteiro somente do primeiro byte
printf("X = %d, Y = %d, Z = %d\n", u.x, u.y, u.z);
return 0;
}
About operators - > e.
The ->
operator is used with pointers, variables that contain memory addresses. When a variable is passed by reference (declaring the parameter as int* i
for example) when referencing variable members within the function, you must use the ->
operator. But if the variable was passed by value , you should use the .
operator to reference the members of struct
or union
(or methods of an object if you are using C ++) . By modifying the example above, we now have:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// O tamanho que a union armazena na memória é o tamanho do maior campo da union
union MinhaUnion {
uint32_t x; // ocupa 4 bytes de memória
uint16_t y; // ocupa 2 bytes de memória
uint8_t z; // ocupa 1 byte de memória
}; // tamanho total que a union ocupa na memória é 4 bytes.
int imprimeUnion(union MinhaUnion un) {
FILE *fp = NULL;
fp = fopen("output.txt", "w");
if (fp != NULL) {
fprintf(fp, "X = %d, Y = %d, Z = %d\n", un->x, un->y, un->z);
return 1;
}
return 0;
}
int main() {
MinhaUnion u;
// coloca o inteiro nos 4 bytes da union
u.x = 123456789;
// passa a union por valor e imprime os campos dela no arquivo
imprimeUnion(u);
return 0;
}
See what the compiler says about the above code:
union_vs_struct.cpp: In function ‘int imprimeUnion(MinhaUnion)’:
union_vs_struct.cpp:18:51: error: base operand of ‘->’ has non-pointer type ‘MinhaUnion’
fprintf(fp, "X = %d, Y = %d, Z = %d\n", un->x, un->y, un->z);
^
union_vs_struct.cpp:18:58: error: base operand of ‘->’ has non-pointer type ‘MinhaUnion’
fprintf(fp, "X = %d, Y = %d, Z = %d\n", un->x, un->y, un->z);
^
union_vs_struct.cpp:18:65: error: base operand of ‘->’ has non-pointer type ‘MinhaUnion’
fprintf(fp, "X = %d, Y = %d, Z = %d\n", un->x, un->y, un->z);
Saying that the operand of ->
(the variable that was passed by value - un
) is not a pointer. Now, if you change ->
to .
or change the parameter declaration in the function so that the variable is passed by reference, the code compiles, it depends on what you intend to do.
About such 'conversion'
Finally, what happens is not a "conversion" between types. But as stated above, because all members share the same initial memory address, you can get 'chunks' from the total memory space of union
and manipulate them through another (variable) field. So if you have the following union
with two fields:
union UNION {
int num;
char[4] vetor;
};
You can treat the second byte of the number as a char by referencing vetor[1]
since vetor
and num
refer to the same starting memory address.