C: Where is union practically used?
Solution 1
I usually use unions when parsing text. I use something like this:
typedef enum DataType { INTEGER, FLOAT_POINT, STRING } DataType ;
typedef union DataValue
{
int v_int;
float v_float;
char* v_string;
}DataValue;
typedef struct DataNode
{
DataType type;
DataValue value;
}DataNode;
void myfunct()
{
long long temp;
DataNode inputData;
inputData.type= read_some_input(&temp);
switch(inputData.type)
{
case INTEGER: inputData.value.v_int = (int)temp; break;
case FLOAT_POINT: inputData.value.v_float = (float)temp; break;
case STRING: inputData.value.v_string = (char*)temp; break;
}
}
void printDataNode(DataNode* ptr)
{
printf("I am a ");
switch(ptr->type){
case INTEGER: printf("Integer with value %d", ptr->value.v_int); break;
case FLOAT_POINT: printf("Float with value %f", ptr->value.v_float); break;
case STRING: printf("String with value %s", ptr->value.v_string); break;
}
}
If you want to see how unions are used HEAVILY, check any code using flex/bison. For example see splint, it contains TONS of unions.
Solution 2
I've typically used unions where you want to have different views of the data e.g. a 32-bit colour value where you want both the 32-bit val and the red,green,blue and alpha components
struct rgba
{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
union
{
unsigned int val;
rgba components;
}colorval32;
NB You could also achieve the same thing with bit-masking and shifting i.e
#define GETR(val) ((val&0xFF000000) >> 24)
but I find the union approach more elegant
Solution 3
For accessing registers or I/O ports bytewise as well as bitwise by mapping that particular port to memory, see the example below:
typedef Union
{
unsigned int a;
struct {
unsigned bit0 : 1,
bit1 : 1,
bit2 : 1,
bit3 : 1,
bit4 : 1,
bit5 : 1,
bit6 : 1,
bit7 : 1,
bit8 : 1,
bit9 : 1,
bit10 : 1,
bit11 : 1,
bit12 : 1,
bit13 : 1,
bit14 : 1,
bit15 : 1
} bits;
} IOREG;
# define PORTA (*(IOREG *) 0x3B)
...
unsigned int i = PORTA.a;//read bytewise
int j = PORTA.bits.bit0;//read bitwise
...
PORTA.bits.bit0 = 1;//write operation
Solution 4
In the Windows world, unions
are commonly used to implement tagged variants, which are (or were, before .NET?) one standard way of passing data between COM objects.
The idea is that a union
type can provide a single natural interface for passing arbitrary data between two objects. Some COM object could pass you a variant (e.g. type VARIANT
or _variant_t
) which could contain either a double
, float
, int
, or whatever.
If you have to deal with COM objects in Windows C++ code, you'll see variant types all over the place.
Solution 5
SDL uses an union for representing events: http://www.libsdl.org/cgi/docwiki.cgi/SDL_Event.
Comments
-
yesraaj over 4 years
I have a example with me where in which the alignment of a type is guaranteed, union max_align . I am looking for a even simpler example in which union is used practically, to explain my friend.
-
yesraaj over 14 yearsI know how to use union, my friend does too, but I want were it is used most commonly
-
jk. over 14 yearsusing a union to cast like this is technically undefined behaviour (although i'm unaware of any implementations which don't actually do what you want here)
-
mouviciel over 14 yearsNever use this if you have to handle big/little endian conversions
-
wrapperm over 14 years@mouviciel: This is not affected by endianness... can you please support your comment, if so..?
-
Alok Singhal over 14 yearsBut
struct rgba
may have padding, and even without padding,sizeof(unsigned int)
may or may not be equal tosizeof(struct rgba)
(4 for no padding). I.e., you probably don't want to do this. -
Alok Singhal over 14 yearsFrom the C standard: "The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
-
David Thornley over 14 years@Alok: Not to mention that the
struct
will haver
,g
,b
, anda
in order (with or without padding), while theunsigned int
byte order will depend on endianness. In other words, this code is not portable and may fail in odd ways when compiling on another processor. -
fbrereto over 14 yearsA common term for this technique is "type punning"
-
nos over 14 yearsDo note that (standard) C does not support this - assigning to one member in a union and then reading from another member is undefined behavior. Compilers/systems implementations do commonly support this though in their own specific ways.
-
Thomas Matthews over 14 yearsIsn't this what polymorphism is for? A base class for the common message content, then each message is a specialization of the base class.
-
Exectron over 14 yearsHowever, in many cases registers or I/O ports are platform-specific, so platform-independent code isn't such a concern. Though I suppose you might write a driver for some hardware that is used on both big-endian and little-endian machines (e.g. a Linux driver for a graphics chip)... in that case you'd know what you're doing I'm sure.
-
wrapperm over 14 yearsThe alignment of the addressable storage unit can be easily determined by a simple program... actually speaking you should have an idea about the architectural endianness and stuff like that before coding for a particular platform...
-
Adriano Varoli Piazza over 14 years@Thomas: you don't have classes in C.
-
zebrabox over 14 yearsThanks for the comments all. As you say this isn't portable ( nor is it intended to be) and relies on many assumptions which I didn't make clear in the post. Typically I wouldn't be using unsigned int but something like a typedef uint32_t i.e where I knew it was 32-bits. I'll amend my post to make this clearer
-
fortran over 14 years@jk The very same undefined behaviour of getting the address, casting to a int pointer and then getting the contents. The only thing undefined here should be the endianness of the float, that is not specified by any standard.
-
GManNickG over 14 yearsDo note that writing to one member of a union then reading from another leads to undefined behavior.
-
josesuero over 14 yearsIn addition to the portability issues, it's also a great way to confuse the compiler with potential aliasing, forcing it to skip a load of otherwise useful optimizations.
-
nos over 14 yearsThis technique blows up when your longs are 64 bit and your floats are not. e.g. linux 64 bit.
-
fortran over 14 years@nos it won't "blow up", you'll keep getting the binary value of the float in either the lower or the upper part of the int (depending on the endiannes) and in the other, maybe trash... you can use a fixed size type if you wish, but this was just an example, not production quality code.
-
nos over 14 yearsI consider my applicatons to "blow up" when it starts producing or processing garbage :-)
-
Roman A. Taycher over 13 yearsie. Tagged unions with pattern matching in c. Do lots of people use unions without ad-hoc type tagging?
-
Sebastian Mach almost 13 yearsThis misses a disclaimer that says "Reading from inactive union members yields undefined behavior".
-
Sebastian Mach almost 13 yearsThough that's using undefined behaviour, even if widely supported.
-
v.oddou almost 10 yearsabout what nos said; I think he means this is undefined behavior because of the strict aliasing rule. this should work when you use char as your "other" union types.
-
Koray Tugay over 9 yearsShouldn't you add alias for DataNode in declaration?