I think the problem was that there were a number of threads in previous posts that did this already. You appeared to be adding to the "noise" of bad practise perhaps without having read the existing posts. The only thing missing is a chapter/verse in the standard, but presumably if one has a copy, it's easy enough to look it up.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.
What are unions good for?
#21 Members - Reputation: 2042
Posted 28 February 2011 - 03:42 AM
#22 Members - Reputation: 2369
Posted 28 February 2011 - 10:20 AM
Yes, that is how such industries operate.Is that the way you drive, or want an airline to operate - "not exactly 100% safe, but generally [..] not a problem"?
Each aircraft launches with hundreds of "issues". They do a cost analysis. How much to fix and replace vs. cost of death. A person is valued at around $2 mil IIRC. Cost of most replacements can quickly go above a plane's worth of people. Same for medical gear, nuclear facilities, chemicals, ...
Just saying...
#23 Members - Reputation: 1551
Posted 28 February 2011 - 02:55 PM
typedef enum
{
VIDEO_SUBSYSTEM=0,
AUDIO_SUBSYSTEM,
MANAGER_SUBSYSTEM,
MAX_SUBSYSTEMS
} etMsgLocation;
typedef struct
{
etAudioType eAudioType;
uint16 SampleRate;
uint16 Channels;
uint32 BufferSize;
uint8 *pBuffer;
} AudioMsg;
typedef struct
{
etVideoFormat eVideoFormat;
union
{
tMpeg4CompressData Mp4Data;
tAviCompressData AviData;
tMpeg2CompressData Mp2Data;
} o;
} tVideoMsg;
typedef struct
{
etMsgLocation eMsgDestination;
etMsgLocation eMsgSource;
union
{
tAudioMsg AudioMsg;
tVideoMsg VideoMsg;
} o;
} tSystemMsg;
tSystemError SendSystemMessage(tSystemMsg *pSystemMsg);
This code compresses audio and video specific informaiton into one structure, but shares the memory location.
Also, the Video Msg type shares memory locations with the different possible compression types.
So, this is one way I commonly see unions used.
---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)
#24 Members - Reputation: 241
Posted 01 March 2011 - 11:29 AM
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 understand that you can cast a type to char*, but it's not compliant to cast char* back into another type.
Suppose I want to bitshift a floating point value. (This is part of a neat little hack used in some 3D engines to approximate the square root operation) I'd have to do something like this right?
float num = 5416.53;
int dest;
char* cNum = reinterpret_cast<char*>(&num);
char* cDest = reinterpret_cast<char*>(&dest);
std::copy(cNum,cNum+sizeof(dest),cDest);
dest >>= 1;
std::copy(cDest,cDest+sizeof(cNum),cNum);
Clearly this is impractical if the reason for using type punning is performance. Seems far more practical to settle for the non-compliant method of using unions. At least it avoids violating strict aliasing rules which are actually enforced on certain major compilers.
Speaking of strict aliasing, how does one use the malloc function when it returns a void pointer? Isn't casting this pointer to another type considered a violation? Or is converting void* to anything else another exception along with cast to char?
#25 Members - Reputation: 982
Posted 01 March 2011 - 01:18 PM
And what is this understanding based on?I understand that you can cast a type to char*, but it's not compliant to cast char* back into another type.
You can cast until the cows come home. What is important is that all accesses to a stored value occur through the same pointer (or "by an lvalue expression that has .. character type" [ANSI C99 6.5#7]).
Which used to be a good idea 10..15 years ago, but I'd expect it to be slower now than the SQRTSS instruction generated by a simple call to fsqrtf().(This is part of a neat little hack used in some 3D engines to approximate the square root operation)
Ooh. Numerous problems with that code:I'd have to do something like this right?
- unnecessary reinterpret_cast
- incorrect end pointer in the second std::copy
- using std::copy, which must be able to handle overlapping ranges, instead of memcpy
- right-shifts on negative integers are undefined
That is anything but clear. Can you justify that statement?Clearly this is impractical if the reason for using type punning is performance.
After fixing the above, I see the following code generated (ICC 12.1):
000000013F7B1058 mov edx,dword ptr [dest]
000000013F7B105B shr edx,1
000000013F7B105D mov dword ptr [dest],edx
Nope. Please see ANSI C99 6.7.3#15.Speaking of strict aliasing, how does one use the malloc function when it returns a void pointer? Isn't casting this pointer to another type considered a violation?
#26 Members - Reputation: 176
Posted 01 March 2011 - 04:23 PM
Fast reciprocal square root may still have a use in performance-critical code, but even that it less useful than it once. If you're using SSE, you may be better off using RSQRTSS or the _mm_rsqrt_ss() intrinsic. (With fast floating point and SSE, the VC++ optimizer might be smart enough to replace 1 / sqrt with a reciprocal square root instruction. I wouldn't count on it, though...)
#27 Members - Reputation: 241
Posted 01 March 2011 - 11:03 PM
That is anything but clear. Can you justify that statement?
After fixing the above, I see the following code generated (ICC 12.1):
000000013F7B1058 mov edx,dword ptr [dest]
000000013F7B105B shr edx,1
000000013F7B105D mov dword ptr [dest],edx
VS2010 wouldn't optimise out the std::copy calls, but after switching to memcpy, it's now producing fully optimised source. (identical to using a straight up cast to int*)
Nope. Please see ANSI C99 6.7.3#15.
What does the standard say on this? And do you know where I can find a copy of the standard for download?
#28 Members - Reputation: 241
Posted 01 March 2011 - 11:12 PM
On x86 processors, that kind of type-punning often has to write the floating-point value to memory, read it into an integer register, perform the integer operation, write it to memory again, and read it back into a floating-point register so it may not be as fast as you think it is. If you're determined to use that kind of approximation, though, there are some slightly better versions. They're faster than the normal sqrt() but less accurate. Setting the floating-point model to "Fast" in Visual C++ allows it to use a native SQRT or SQRTSS instruction and avoid the normal library function call.
Yeah it's not worth the trouble in this day and age when you can simply enable SSE2 and FP:fast. I should have mentioned a more relevant application of type punning. For example, generating a hash values out of non-integer types.
#29 Members - Reputation: 982
Posted 02 March 2011 - 02:47 PM
Reading single paragraphs is not the path to wisdomWhat does the standard say on this?
http://lmgtfy.com/?q...2+%2Bc+standardAnd do you know where I can find a copy of the standard for download?
I don't think you'll find anything but the draft C++0x standard for free legal download, but $30 should be affordable.
Ah, that's a good example.For example, generating a hash values out of non-integer types.






