Casting a structure to an int

C

candy_init

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
 
T

tmp123

Hello,

See inserted comments:

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

Sizeof of my_union? and sizeof of long?
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

"cast anything or the first bytes of anything or even all it and some
parts of who knows what". Practical, nice and dangerous.

Kind regards.
 
G

Guillaume

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))

A perfect example of what shouldn't be done.
 
B

Ben Pfaff

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;

In a cast expression, the expression whose value is cast must
have a scalar type, but a union is not a scalar type. (A scalar
type is an arithmetic type or a pointer type.)
 
E

Eric Sosman

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))

"Anything?"

CAST(void, stdin)

CAST(char*, printf)

CAST(double, 42)

... and I imagine other examples could be dreamed up.

But even for those cases where there's no compile-time
error, the whole idea is wrong-headed. All CAST attempts
to do is re-interpret the bits of one thing as if they had
some other type. There's no attempt to convert, no concern
for safety, and no reason to rely on whatever result you
might happen to get. It's a Bad Idea, almost always --
and you can delete the "almost" if you're trying to write
code that's even marginally portable.
 
M

Michael Mair

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
 
R

Robin Haigh

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))



oh dear. Bracket in the wrong place -- needs to be

#define CAST(new_type,old_object) (*(new_type *)&(old_object))


or it won't always work.

(It won't work with array types either, but you can get round that with a
typedef)

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;

You can't convert a variable. You can only fetch its value and convert
that. But you can only do that with a scalar. Converting the "value" of an
array or struct or union doesn't make any sense
 
M

Michael Mair

Robin said:
oh dear. Bracket in the wrong place -- needs to be

#define CAST(new_type,old_object) (*(new_type *)&(old_object))


or it won't always work.

(It won't work with array types either, but you can get round that with a
typedef)

What do you mean?

#include <stdio.h>

#define UNSAFE_CAST(new_type, old_object) \
(*((new_type *)&(old_object)))

int main (void)
{
short foo[5] = {42, 1, 2, 3, 4};

printf("&foo[0]: %p, &foo: %p\n",
(void *)&foo[0], (void *)&foo);
printf("foo[0]: %d\n", UNSAFE_CAST(short,foo));

return 0;
}

<snip!>

Cheers
Michael
 
K

Kenneth Brody

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?
[...]

You cannot simply cast from a union to a long, which is what you are
trying to do with the direct cast.

However, the CAST() macro does not directly cast from a union to a
long. Rather, it takes the address of the union, casts that to a
"long *", and then dereferences the pointer.

CAST(long,my_union)

expands to

*(long *)&my_union

Note, of course, that the above is not a very "safe" thing to be doing.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
R

Robin Haigh

Michael Mair said:
What do you mean?

I only meant, if new_type is int[3], you'll get (int[3]*), which will be a
syntax error. You can't always generate the name of a pointer type just by
adding a * on the end of something.
 
M

Michael Mair

Robin said:
What do you mean?

I only meant, if new_type is int[3], you'll get (int[3]*), which will be a
syntax error. You can't always generate the name of a pointer type just by
adding a * on the end of something.

I see; thank you for the clarification :)

Cheers
Michael
 
K

Keith Thompson

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))
[...]

The name CAST is misleading. A C cast oerator specifies a
*conversion*. This macro reinterprets the operand's representation as
if it were of a specified type, which is a very different thing.
(Some conversions might be implemented that way, but numeric
conversions, for example, are not.)
 
P

Peter Nilsson

Though not necessarily in a portable fashion.
#define CAST(new_type,old_object) (*((new_type *)&old_object))
[...]

The name CAST is misleading. A C cast oerator specifies a
*conversion*.

Yes. More specifically, a cast is an _explicit_ conversion. What could
be
more explicit than an all caps function macro that converts an lvalue
of
one type to an lvalue of another type?
This macro reinterprets the operand's representation as
if it were of a specified type, which is a very different thing.

Bjarne Stroustrup (a notable C programmer) didn't think so. He
labelled one of the C++ operators reinterpret_cast, not reinterpret
or reinterpret_conversion.
(Some conversions might be implemented that way, but numeric
conversions, for example, are not.)

As I see it, a conversion usually involves two things: a change of
type, and a mapping of representation. The latter being a no-op
does not mean the 'change' is not a 'conversion'.

Perhaps the point you want to make is that, in C, casts produce
(old school) rvalues, so maybe REINTERPRET_CAST or
REINTERPRET_AS would be a better name?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top