Jump to content

  • Log In with Google      Sign In   
  • Create Account


What are unions good for?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
28 replies to this topic

#1 freeworld   Members   -  Reputation: 321

Like
0Likes
Like

Posted 25 February 2011 - 05:18 PM

Bored and reading in my favourite room ;) I noticed out of all the c/c++ books I have only one even spends a paragraph talking about unions, and from the little reading here I understand what unions are and what they do... but other than for defining color values that can acces individual channels or the whole color I can't think what they would be good for.

What would you use a union for? Is it just depricated idea? even with the color idea, a class/struct could easily do the same thing and probably better.
[ dev journal ]
[ current projects' videos ]
[ Zolo Project ]
I'm not mean, I just like to get to the point.

Sponsor:

#2 Antheus   Members   -  Reputation: 2385

Like
0Likes
Like

Posted 25 February 2011 - 05:23 PM

They allow different interpretation of same memory location.

#3 freeworld   Members   -  Reputation: 321

Like
0Likes
Like

Posted 25 February 2011 - 05:38 PM

They allow different interpretation of same memory location.


I know what they do, I was more interested in how they would be used in the real world and why? Just trying to further my knowledge.
[ dev journal ]
[ current projects' videos ]
[ Zolo Project ]
I'm not mean, I just like to get to the point.

#4 Nanoha   Members   -  Reputation: 296

Like
0Likes
Like

Posted 25 February 2011 - 05:58 PM

Some form of event maybe with an "additional info" variable.

additionalInfo.Int = 10;
additionalInfo.Float = 10.0f

Obviously you can just cast but I believe you can also have type that take a larger number of bytes (such as a double) but use only a bit of it (unsigned int).

additionalIfno.Double = 1.0;
additionalInfo.UnsignedInt = 10;

double takes up more memory than an unsigned int

#5 freeworld   Members   -  Reputation: 321

Like
0Likes
Like

Posted 25 February 2011 - 06:04 PM

Some form of event maybe with an "additional info" variable.

additionalInfo.Int = 10;
additionalInfo.Float = 10.0f

Obviously you can just cast but I believe you can also have type that take a larger number of bytes (such as a double) but use only a bit of it (unsigned int).

additionalIfno.Double = 1.0;
additionalInfo.UnsignedInt = 10;

double takes up more memory than an unsigned int


I believe that is incorrect... the union should take up the space of the largest variable?
[ dev journal ]
[ current projects' videos ]
[ Zolo Project ]
I'm not mean, I just like to get to the point.

#6 Tachikoma   Members   -  Reputation: 548

Like
7Likes
Like

Posted 25 February 2011 - 07:44 PM

You can use unions for handy syntactic sugar purposes. Probably the most useful aspect of unions. For example:

class vec4
   {
   public:
   union {float X, U, R;};
   union {float Y, V, G;};
   union {float Z, S, B;};
   union {float W, T, A;};
   };

vect4 Colour;
Colour.R = 1.0f; //Same as Colour.X = 1.0f;
Colour.G = 1.0f;  //Same as Colour.Y = 1.0f;
Colour.B = 1.0f;  //Same as Colour.Z = 1.0f;
Colour.A = 1.0f;  //Same as Colour.W = 1.0f;

vect4 Point;
Point.X = 0.123f;
 Point.Y = 0.23f;
 Point.Z = 0.3f;
 Point.W = 1.0f;
 
//...etc

This allows you to use this vector class with XYZW notation, or RGBA, or UVST, which is similar how you can access vector components in vertex/fragment shaders.

Another use of union notation is mapping larger data types over a collection of smaller types. For example,

union 
   {
   int I;
   char C[sizeof(int)];
   } Test;

You can access different parts of the integer without masking. Note that there are pitfalls with this, the mapping order of the array will be architecture dependent. In fact, you can use this type of union to test for machine endian-ness. For example:

Test.I = 0x000F;
if (Test.C[0] == 0x0F)
   {
   //Little endian CPU
   }
else
   {
   //Big endian CPU
   }

You can map float data types across integers, use bit mask manipulation on the integer mapping to modify the float data.

union
   {
   float F;
   int32 I;
   } Blah;

Blah.F = -1.0f;
Blah.I &= 0x7FFFFFFF; //Clear sign bit (warning: machine dependent operation)

float f = Blah.F; //Should be 1.0f now

I have used unions in a similar manner to convert exotic 80-bit long double types to 64-bit double using bit manipulation.

It's quite rare when you need to do something like this, and its best to avoid if you can.
Latest project: Sideways Racing on the iPad

#7 taz0010   Members   -  Reputation: 248

Like
3Likes
Like

Posted 25 February 2011 - 11:11 PM

Isn't using unions in this way undefined behaviour according to the standard? I was told that the standard only supports accessing the element in a union which was last written to, in which case it's only safe to use unions to save space. Combine this with the rules on strict aliasing, and pretty much any form of type pruning relies on compiler specific behaviour.

Are there specific compilers where using unions for type pruning does not work though?



#8 Tachikoma   Members   -  Reputation: 548

Like
0Likes
Like

Posted 26 February 2011 - 12:32 AM

I was told that the standard only supports accessing the element in a union which was last written to, in which case it's only safe to use unions to save space.

I believe you have point there. Personally I haven't seen any compiler that does not exhibit the behaviour I posted earlier. I dare say, if the bit-field size of each union member is identical, and that their mapping is guaranteed to be at the same physical memory location, then you can expect this behaviour to be consistent. Unless of course there is some kind of data conversion behind the scenes when it's written to memory. I've seen unions used as a crude reinterpret_cast mechanism in C; not exactly 100% safe, but generally they were not a problem if some precautions were taken.
Latest project: Sideways Racing on the iPad

#9 Prune   Members   -  Reputation: 187

Like
0Likes
Like

Posted 26 February 2011 - 02:23 AM

Unions can also help avoid aliasing problems when accessing both different bytes of a multibyte type and the type itself (source: http://locklessinc.com/articles/mutex_cv_futex/ )

"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)

#10 djofdifjpodjfpodkpofdpofpd   Members   -  Reputation: 120

Like
0Likes
Like

Posted 26 February 2011 - 05:36 AM

Isn't using unions in this way undefined behaviour according to the standard? I was told that the standard only supports accessing the element in a union which was last written to, in which case it's only safe to use unions to save space. Combine this with the rules on strict aliasing, and pretty much any form of type pruning relies on compiler specific behaviour.

Are there specific compilers where using unions for type pruning does not work though?



Yes that and most of what has been posted here is undefined behaviour according to the standard. You really should have an identifier which signals which element is currently stored in the union, then only read this element and none of the others.

#11 InvalidPointer   Members   -  Reputation: 1271

Like
0Likes
Like

Posted 26 February 2011 - 09:06 AM

Unions are also pretty useful in pooling-- assuming your pooled objects are big enough, you can temporarily reinterpret them as being, say, a node in a doubly-linked list. This also has the added benefit of being standards-compliant!
clb: At the end of 2012, the positions of jupiter, saturn, mercury, and deimos are aligned so as to cause a denormalized flush-to-zero bug when computing earth's gravitational force, slinging it to the sun.

#12 Jan Wassenberg   Members   -  Reputation: 982

Like
3Likes
Like

Posted 26 February 2011 - 09:54 AM

and pretty much any form of type pruning relies on compiler specific behaviour.

You mean "type punning", for which there are actually two standard and perfectly safe methods - serializing through char*, which has a special dispensation concerning aliasing, or memcpy.

I've seen unions used as a crude reinterpret_cast mechanism in C; not exactly 100% safe, but generally they were not a problem if some precautions were taken.

Is that the way you drive, or want an airline to operate - "not exactly 100% safe, but generally [..] not a problem"?
I don't see why an incorrect and illegal solution is preferable to memcpy, which is hardly more complicated.

Yes that and most of what has been posted here is undefined behaviour according to the standard. You really should have an identifier which signals which element is currently stored in the union, then only read this element and none of the others.

Good advice.

Incidentally, I often engage in bit-twiddling, and have yet to find a helpful and safe use for unions in that context.
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3

#13 Bearhugger   Members   -  Reputation: 449

Like
0Likes
Like

Posted 27 February 2011 - 02:22 AM

You use unions to save memory. Think of a RPG. An item can be a potion, a weapon, an armor, a quest item, a scroll, a permanent stat up, etc. So an item needs to provide a member for health healing, mana healing, and buffing or debuffing in case it is a potion, attack power, chance to hit, and critical hit chance in case it's a weapon, armor class, magic resistance and evasion in case it's armor, spell to use for scrolls, etc. So that's a lot of variables even though you only ever use two or three at a time. This is a very good place to use a union, where the specific variables are stored into a union of structs, each containing the variables of a particular class of item.

Of course, using unions and data structs is an older style of programming. Polymorphism and real-time type information are a much more powerful way to make similar items with different content. However, in the example above, inventory is something you probably want serialized, and serializing polymorphic objects isn't always simple, whereas a simple byte-by-byte copy operation will do the trick for unions and data structures, so it's not to say there's no advantage to unions versus polymorphism.

#14 wqking   Members   -  Reputation: 756

Like
1Likes
Like

Posted 27 February 2011 - 05:57 AM

Others may have shown the most common using of union.

Here is a less common but also very useful trick:

union WithOrWithoutName {
  TypeA * pa;
   TypeB * pb;
 };

Then you can use a same pointer in both type of TypeA and TypeB, no needing any type cast.
Qt used this trick in some container classed, I also used it in my code.

http://www.cpgf.org/
cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.
v1.5.5 was released. Now supports tween and timeline for ease animation.


#15 Jan Wassenberg   Members   -  Reputation: 982

Like
5Likes
Like

Posted 27 February 2011 - 07:50 AM

Please don't write, much less advocate, such non-standard-conforming code.
Both C99 and C++03 say only one union member can be active at a time and provide an explicit exception for accessing a common sequence (usually a type tag) in Bearhugger's union-of-structs. This exception would not be necessary if it were generally legal to access a different field than was last written.

It's important to stamp out such sloppy and senseless non-conforming code because it interferes with aliasing analysis (arguably one of the most important optimizations).
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3

#16 Tachikoma   Members   -  Reputation: 548

Like
0Likes
Like

Posted 27 February 2011 - 09:01 AM

I had a proper read though the C99 standards the other day and I have to concede, it's probably best to abandon the examples I posted earlier. It's real shame though, suddenly unions have become less useful in my mind.
Latest project: Sideways Racing on the iPad

#17 Ravyne   Crossbones+   -  Reputation: 5690

Like
0Likes
Like

Posted 27 February 2011 - 01:37 PM

A common use is to lay out a friendlier structure over the top of a larger type which facilitates, for example, SIMD operations, a'la:

struct Vec4{
    union {
        __m128 v;
        struct { float x, y, z, w; };
    };
};


#18 djofdifjpodjfpodkpofdpofpd   Members   -  Reputation: 120

Like
2Likes
Like

Posted 27 February 2011 - 02:32 PM

A common use is to lay out a friendlier structure over the top of a larger type which facilitates, for example, SIMD operations, a'la:

struct Vec4{
    union {
        __m128 v;
        struct { float x, y, z, w; };
    };
};



Can people stop posting this crap as if it is defined, or at least state that it is platform specific. Ravyne has taken this to another level filled with even more undefined/illegal goodness, requiring language extensions.
Maybe this is should be in the FAQ.

#19 Ravyne   Crossbones+   -  Reputation: 5690

Like
0Likes
Like

Posted 27 February 2011 - 11:46 PM

Fair enough that I didn't take great pains to enumerate potential downsides, but to be fair I gave that code no endorsement either -- I simply put it forward as one (rather common) example of its use. I didn't even pull that from my own code, but did a quick Google search and pulled it from the first hit, which happened to be a thread here on gamedev. I could have taken the time to vet the code, but I was in a rush.

In any event, if you have an issue with the code itself, lets pick it apart and demonstrate what's wrong with this (again, common -- even if platform specific) practice, rather than leveling near-accusations that I've undertaken this enterprise as some sort of malice or ignorance-driven desire to mislead.

#20 kdmiller3   Members   -  Reputation: 176

Like
0Likes
Like

Posted 28 February 2011 - 01:27 AM

A union like that between a struct and a native SIMD type can be hard to avoid in performance-critical code (such as a vector/matrix math library on a console) even though it's platform- and even compiler-specific. On the other hand, you're probably better off writing accessor functions using SIMD intrinsics since you can avoid writing a SIMD register to memory and reading a component back into a floating-point register.

Union are dangerous power tools that should be used only when necessary and when you know what you're getting yourself into. Most of the time, there are cleaner or safer ways to attack the problem. :)




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS