If I were you, I'd stick with multiplicative-additive operations in the packing/unpacking functions. Something like this
unsigned long RGBA2DWORD(int iR, int iG, int iB, int iA)
{
return ((iA * 256 + iR) * 256 + iG) * 256 + iB;
}
with a symmetrical unpacking function
RGBA DWORD2RGBA(unsigned long dwColor)
{
RGBA tmp; /* why did you declare it static??? */
tmp.B = dwColor % 256; dwColor /= 256;
tmp.G = dwColor % 256; dwColor /= 256;
tmp.R = dwColor % 256; dwColor /= 256;
tmp.A = dwColor % 256; /* dwColor /= 256; */
return tmp;
}
Note that there's only one "magic constant" in the whole code.
Of course, if you have an external specification that is written in terms of bit patterns in the packed data, a version based on bit and shift opertions might be preferrable. Still
unsigned long RGBA2DWORD(int iR, int iG, int iB, int iA)
{
return (((((iA << 8) + iR) << 8) + iG) << 8) + iB;
}
RGBA DWORD2RGBA(unsigned long dwColor)
{
RGBA tmp; /* why did you declare it static??? */
tmp.B = dwColor & 0xFF; dwColor >>= 8;
tmp.G = dwColor & 0xFF; dwColor >>= 8;
tmp.R = dwColor & 0xFF; dwColor >>= 8;
tmp.A = dwColor & 0xFF; /* dwColor >>= 8; */
return tmp;
}
has much less "magic constants".
Now you can wrap the repetivie actions/subexpressions in macros or, better, inline functions and arrive at very compact and readable packer/unpacker.