By the way: sometimes there might be good reasons to use unions.
Here is an example to set the most significant byte of an unsigned
long long to 0x12U.
I'm pretty sure that nothing will be faster than this ->
typedef unsigned long long my_ull;
union ACCESS_FAST {
my_ull v;
unsigned char ca[sizeof(my_ull)];
};
my_ull var;
((union ACCESS_FAST *) &var)->ca[sizeof(union ACCESS_FAST)-1] =
0x12U;
printf("%llx\n", var);
Is there any problem with this code?
union ACCESS_FAST var2;
var.ca[sizeof(var2.ca)-1] = 0x12U;
printf("%llx\n", var2.v);
Event better is this, which uses the macro MSB_LVALUE:
#include <stdio.h>
#define MSB_LVALUE(var) (((unsigned char*)&(var))[sizeof(var)-1])
int main(void)
{
typedef unsigned long long my_ull;
my_ull var2 = (my_ull)-1ULL;
MSB_LVALUE(var2) = 0x12U;
printf("%llx\n", var2);
unsigned i = (unsigned)-1U;
MSB_LVALUE(i) = 0x12U;
printf("%x\n", i);
}
Nothing wrong with this, right?
Thanks.
Ah sorry... the above does NOT set the MSB. It would happen to do that
only on little endian machines, but not on big endian.
The code above rather does something else: It sets the largest-
addressed bytes inside the variable.
I cannot see anyway to optimize access to the real MSB (most signif.
byte) in a platform-independant way... in the same way as a union
would provide, unless I also check endianness.
If I use the "normal" way, there always seems to be a lot of shifting
involved.
But anyway... here is a nice macro hack, that does the shifting etc.
for all unsigned types:
#include <stdio.h>
#include <limits.h>
#define GET_TYPE_INT_OR_LARGER_0(var) (var & 0)
#define GET_SHIFT_CHAR_BIT(var) ((sizeof(var) >= sizeof(int)) ?
CHAR_BIT : (CHAR_BIT * (sizeof(int)-sizeof(var)+1)))
/* works only with unsigned */
#define SET_MSB_RVALUE(var, msb) ((var &
((GET_TYPE_INT_OR_LARGER_0(var) -1U) >> GET_SHIFT_CHAR_BIT(var))) |
((GET_TYPE_INT_OR_LARGER_0(var) + msb) << (CHAR_BIT*(sizeof(var)-1))))
#define MSB_VAL 0X12U
int main(void)
{
typedef unsigned long long my_ull;
my_ull var2 = (my_ull)-1ULL;
var2 = SET_MSB_RVALUE(var2, MSB_VAL);
printf("%llx\n", var2);
unsigned i = (unsigned)-1U;
i = SET_MSB_RVALUE(i, MSB_VAL);
printf("%x\n", i);
unsigned short s = (unsigned short)-1U;
s = SET_MSB_RVALUE(s, MSB_VAL);
printf("%x\n", s);
unsigned char c = (unsigned char)-1U;
c = SET_MSB_RVALUE(c, MSB_VAL);
printf("%x\n", c);
return 0;
}
You may be interested in the tricks used, to make the macro work for
all unsigned types... from "unsigned char" to "unsigned long long".