ca********@yahoo.com wrote:
I recently came across the following CAST macro which can cast anything
to any other thing:
#define CAST(new_type,old_object) (*((new_type *)&old_object))
union
{
char ch[4];
int i[2];
} my_union;
long longvar;
longvar = (long)my_union; Illegal cast
//////////////// ILLEGAL
longvar = CAST(long, my_union); Legal cast
I understands that why the CAST macro works but I cannot understands
that what is the problem in the following casting :
longvar = (long)my_union;
Can somebody please tell me that what is the problem in the above
casting mechanism?
PS This is not an assignment. I took this code from the following
link:
http://paul.rutgers.edu/~rhoads/Code/cast_anything.c
First of all: This is not a safe technique.
long longvar = (long)my_union;
is just an explicit version of
long longvar = my_union;
because a cast is just an explicit conversion.
As there is no way to convert an arbitrary aggregate type
into an integer type, your compiler will complain.
So, what is the "trick" with the CAST macro?
You do not take the "value" of the aggregate but the
_representation_.
CAST(long, my_union);
tells the compiler to take the bit pattern at &my_union
and pretend that it is the bit pattern of a long.
When does this work guaranteedly?
Whenever the first argument of the CAST macro is
1) of type unsigned char or
2) if the second argument is of structure type, of
the type of the first member
3) if the second argument is of union type, of the
type of the member which has been last written to
4) if the second argument is of array type, of the
type of the array elements
5) a "recursive mixture" of 2)-4)
Example for 5)
struct { union { short foo[5]; float bar[3] } baz } qux;
short firstfoo;
qux.baz.foo[0] = 7;
firstfoo = CAST(short, qux);
There are other times when this works but this is a
implementation dependent thing.
When will it break?
Imagine your example for
sizeof (long) == 8
sizeof (int) == 2 or sizeof (int) == 4
and alignment requirement "long address can be divided
by 8 without remainder, int address can be divided by
2 (or 4, respectively) without remainder".
Then the above can go wrong
a) if the union has an address accommodating the alignment
requirement of int but not of long
b) sizeof (int) == 2: sizeof (long) > sizeof my_union, i.e.
the "CAST" accesses storage which does not belong to
my_union. This gives you either an arbitrary value for
longvar or an access to storage which does not belong
to your program
c) long has a trap representation which has been generated
using my_union.ch
d) a combination of a)-c)
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.