How union share the same memory

MrAl

Joined Jun 17, 2014
11,396
The way i understood it is that a union is a sneaky way of using the same name for several types of variables while only one type can be used at any given time with that name.
So if we had a union "MyVar" that was declared as both float and byte we could store EITHER a byte or a float there, something we cant normally do with either a regular float variable or regular byte variable. Note that we can NOT store BOTH there at the same time, we can only store one at a time. If we store a byte there and then store a float there, the float overwrites the byte and the byte is no longer available for retrieval, and if we store a float there and then store a byte, the byte overwrites the float and the float is no longer available for retrieval.
So whatever type we store there last is the only type available for reading.
For example if we store 0x12 we have only 0x12 available, and if we later store 1.234 there then we loose the 0x12 and only retain the 1.234. If we then later store 0x34 there then we lose the 1.234 and only have the 0x34 available.

We can make our own custom unions through the use of allocated memory, but i think the union is more compiler friendly.
I cant remember the errors associated with unions offhand though, but with allocated memory there will be none as long as you dont write outside of the memory space allocated. This means that if you allocated 4 bytes you can store a 32 bit integer there or 4 distinct bytes. There is a chance this might be the same with a union though if we declare one integer or 4 bytes but i dont remember if that is possible or not.
 

WBahn

Joined Mar 31, 2012
29,979
The way i understood it is that a union is a sneaky way of using the same name for several types of variables while only one type can be used at any given time with that name.
So if we had a union "MyVar" that was declared as both float and byte we could store EITHER a byte or a float there, something we cant normally do with either a regular float variable or regular byte variable. Note that we can NOT store BOTH there at the same time, we can only store one at a time. If we store a byte there and then store a float there, the float overwrites the byte and the byte is no longer available for retrieval, and if we store a float there and then store a byte, the byte overwrites the float and the float is no longer available for retrieval.
So whatever type we store there last is the only type available for reading.
For example if we store 0x12 we have only 0x12 available, and if we later store 1.234 there then we loose the 0x12 and only retain the 1.234. If we then later store 0x34 there then we lose the 1.234 and only have the 0x34 available.
You're implying (don't know if you meant to) that we could go

MyVar = 0x12; // Store an int
or
MyVar = 1.234; // Store a float

We can't, because the compiler doesn't know how to represent either value in memory. We must use the member name, as well.

MyVar.myInt = 0x12; // Store an int
or
MyVar.myFloat = 1.234; // Store a float

I wouldn't consider this to be using the same name.

The "sneekiness" is that we are using the same memory, as you describe.

We can make our own custom unions through the use of allocated memory, but i think the union is more compiler friendly.
I cant remember the errors associated with unions offhand though, but with allocated memory there will be none as long as you dont write outside of the memory space allocated. This means that if you allocated 4 bytes you can store a 32 bit integer there or 4 distinct bytes. There is a chance this might be the same with a union though if we declare one integer or 4 bytes but i dont remember if that is possible or not.
The problem (or one thereof) with rolling your own unions is that you are now responsible for all of the type casting that is involved, and that is very error-prone; since you can't dereference a void pointer, there's a lot of type casting to do, too.
 

xox

Joined Sep 8, 2017
838
The way i understood it is that a union is a sneaky way of using the same name for several types of variables while only one type can be used at any given time with that name.
So if we had a union "MyVar" that was declared as both float and byte we could store EITHER a byte or a float there, something we cant normally do with either a regular float variable or regular byte variable. Note that we can NOT store BOTH there at the same time, we can only store one at a time. If we store a byte there and then store a float there, the float overwrites the byte and the byte is no longer available for retrieval, and if we store a float there and then store a byte, the byte overwrites the float and the float is no longer available for retrieval.
So whatever type we store there last is the only type available for reading.
For example if we store 0x12 we have only 0x12 available, and if we later store 1.234 there then we loose the 0x12 and only retain the 1.234. If we then later store 0x34 there then we lose the 1.234 and only have the 0x34 available.

We can make our own custom unions through the use of allocated memory, but i think the union is more compiler friendly.
I cant remember the errors associated with unions offhand though, but with allocated memory there will be none as long as you dont write outside of the memory space allocated. This means that if you allocated 4 bytes you can store a 32 bit integer there or 4 distinct bytes. There is a chance this might be the same with a union though if we declare one integer or 4 bytes but i dont remember if that is possible or not.
Here's another example, using unions to extend otherwise twiddle-centric API's:

Code:
#include "stdio.h"

enum
{
 flag1 = 1, 
 flag2 = flag1 << 1, 
 flag3 = flag2 << 1, 
 flag4 = flag3 << 1
};

typedef union
{
 struct
 {
  unsigned flag1 : 1;
  unsigned flag2 : 1;  
  unsigned flag3 : 1;
  unsigned flag4 : 1;  
 } 
  bits;
 unsigned mask;
}
 info;

#define confirm(value) printf("%s : %s\n", #value, value ? "PASS" : "FAIL")
#define deny(value) confirm(!(value))

int main(void)
{
 info data = { 0 };
 data.bits.flag1 = 1;
 confirm(data.mask & flag1);
 data.bits.flag1 = 0;
 deny(data.mask & flag1);
 data.mask |= flag3;
 confirm(data.bits.flag3);
 data.bits.flag3 = 0;
 deny(data.mask & flag3);
}
 

MrAl

Joined Jun 17, 2014
11,396
You're implying (don't know if you meant to) that we could go

MyVar = 0x12; // Store an int
or
MyVar = 1.234; // Store a float

We can't, because the compiler doesn't know how to represent either value in memory. We must use the member name, as well.

MyVar.myInt = 0x12; // Store an int
or
MyVar.myFloat = 1.234; // Store a float

I wouldn't consider this to be using the same name.

The "sneekiness" is that we are using the same memory, as you describe.



The problem (or one thereof) with rolling your own unions is that you are now responsible for all of the type casting that is involved, and that is very error-prone; since you can't dereference a void pointer, there's a lot of type casting to do, too.
Repl

Yeah that's it. I have not used a union in years now.

I had to roll my own everything at one point or another as i come from the minimal asm era when i even had to roll my own assembler. I also had to roll my own floats (sounds strange right) because the 'new' AMD processor i had gotten back sometime ago could not handle floats properly due to the reduced floating point core count in the now notorious AMD 4 to 8 core processors. Along with that i also had to roll my own floats to integers because the conversion for that was also way slow once i got the 'new' AMD processor.
It is interesting but yes you have to be very aware of what goes where.
But also when i need an array with variable length elements for storing things like file paths i have no choice but to use allocated memory.
It is also possible to write wrapper functions to handle the i/o to the custom union(s). That greatly helps handle that part of it.
 

WBahn

Joined Mar 31, 2012
29,979
Repl

Yeah that's it. I have not used a union in years now.

I had to roll my own everything at one point or another as i come from the minimal asm era when i even had to roll my own assembler. I also had to roll my own floats (sounds strange right) because the 'new' AMD processor i had gotten back sometime ago could not handle floats properly due to the reduced floating point core count in the now notorious AMD 4 to 8 core processors. Along with that i also had to roll my own floats to integers because the conversion for that was also way slow once i got the 'new' AMD processor.
It is interesting but yes you have to be very aware of what goes where.
But also when i need an array with variable length elements for storing things like file paths i have no choice but to use allocated memory.
It is also possible to write wrapper functions to handle the i/o to the custom union(s). That greatly helps handle that part of it.
I have a header file called dirtyd.h (and dirtyd.c) -- short for "dirty deed done dirt cheap" -- that is a collection of utilities and macros and you name it that has grown over the last nearly three decades. Included are some of the capabilities you mention, such as getting a string of arbitrary length from an input device and allocating the memory needed for it. Also dynamically allocating multi-dimensional arrays so that the multi-square-bracket array indexing will work correctly within functions even though only the pointer to the array is passed. Lots of cool little things, some of which have been overtaken by better approaches but are still in there for backwards compatibility.

I have a separate set of files for working with object-like structures that have some pretty sophisticated macros that make creating and maintaining such objects and their methods pretty straightforward and allow for the methods to validate that they are being called on an object of the correct type.
 

Thread Starter

mukesh1

Joined Mar 22, 2020
68
What platform are you on???? It would appear that your int is also 32 bits....
I appreciate all of you contribution. we can define a union with many members, but only one member can contain a value at any given time" The size of the union will be that of the largest member.

1586434707273.png
 

MrChips

Joined Oct 2, 2009
30,720
I think of union when I want to be able to describe an object in different ways. I do this often when creating graphics.

For example, a rectangle can be described in two ways:

1) using two diagonal corners, (left, top) and (right, bottom)
2) using a corner and width and height

Thus, I create two separate structures for a box,
1) a box using diagonal corners
2) a box using a corner and size.

Then I create a union using the two definitions.

typedef struct
{
short left;
short top;
short right;
short bottom;
}sBox_corners;

typedef struct
{
short left;
short top;
short width;
short height;
}sBox_size;

typedef union
{
sBox_corners corner;
sBox_size box;
}sRect;
 
Top