pointer type casting

C

cheesiong

Can anyone explain the following codes?
especially the cast of pointer type.
What does it really mean. Thanks.

float f1;
unsigned long l1;

f1=4.5;

l1=*(unsigned long*)&f1;
 
M

Martin Ambuhl

Can anyone explain the following codes?
especially the cast of pointer type.
What does it really mean. Thanks.

float f1;
unsigned long l1;

f1=4.5;

l1=*(unsigned long*)&f1;

It means, among other things, that the coder is trying to make his
program commit suicide.

On the surface, he is taking the address of the float f1,
using it as a pointer to an unsigned long,
and storing what ever is pointed at into an unsigned long.

Here is why this playing fast-and-loose with these types is a bad thing:
1) There is no requirement for floats to be stored in any particular
way. The same bit pattern could mean different values for f1 on
different platforms or even the same platform and a different compiler.
2) There is no requirement for unsigned longs to be stored in any
particular way. The same bit pattern could mean different values for l1
on different platforms or even the same platform and a different compiler.

1 & 2) together mean that you don't have a clue what it means to treat a
sequence of bits stored in a float as an unsigned long.

3) [and this is the killer] There is no requirement about the relative
amounts of space that a float and an unsigned long consume. In
particular, it would not be surprising for floats to be shorter than
unsigned longs. That means that using the address of a float as the
address of an unsigned long involves using memory which is not part of
the float object. This is a very bad thing.

This kind of code depends on a particular representation of floats, a
particular representation of unsigned longs, and on the assumption that
sizeof(float) >= sizeof(unsigned long) and probably that sizeof(float)
== sizeof(unsigned long).

This is the kind of code that should get a programmer fired in many
cases. Even if the specification of a program is, at the moment, for a
particular piece of hardware with a particular software configuration,
writing code like this depends on there never being a hardware or
software modification. This is a reasonable bet for embedded software
at best.
 
P

pete

Can anyone explain the following codes?
especially the cast of pointer type.
What does it really mean. Thanks.

float f1;
unsigned long l1;

f1=4.5;

l1=*(unsigned long*)&f1;

Most likely, it means that the programmer didn't know that
ll = fl;
is the correct way to assign a value from
that float object to that unsigned long object.

One of the possible problems with your code example
is that &f might not be aligned for a long type
which means that ((unsigned long*)&f1) might be undefined.
 
C

CBFalconer

Can anyone explain the following codes? especially the cast of
pointer type. What does it really mean. Thanks.

float f1;
unsigned long l1;

f1=4.5;

l1=*(unsigned long*)&f1;

It means the programmer is incompetent, and possibly also
incontinent. The last statement is meaningless, and invokes
undefined behaviour.
 
K

Keith Thompson

pete said:
Most likely, it means that the programmer didn't know that
ll = fl;
is the correct way to assign a value from
that float object to that unsigned long object.

I don't think that's the most likely explanation. I can easily
imagine a programmer not knowing whether a cast is necessary when
assigning a float value to an unsigned long object, but the use of
pointer casts tells me that the programmer was deliberately trying to
examine the representation of f1 as if it were of type unsigned long.

In some contexts, that might even be a reasonable thing to do, though
it's not necessarily the best way to do it, because ...
One of the possible problems with your code example
is that &f might not be aligned for a long type
which means that ((unsigned long*)&f1) might be undefined.

Here's a mostly reasonable program that incorporates the above code:

#include <stdio.h>
int main(void)
{
if (sizeof (float) == sizeof (unsigned long)) {
float f1 = 4.5;
unsigned long l1;

l1 = *(unsigned long*)&f1;
printf("f1 = %g, l1 = %lx\n", f1, l1);
if (l1 == 0x40900000) {
puts("Looks like 32-bit IEEE floating-point");
}
else {
puts("Unknown format");
}
}
else {
puts("Size mismatch");
}
return 0;
}

As you point out, alignment is a potential problem, so I'd probably
use memcpy() rather than pointer tricks. I'd probably also check more
than one value, and try harder to find a matching integer type if
unsigned long doesn't match -- but maybe I only care about some
limited set of implementations.

In fact, I have a program I use sometimes that does something similar
to the above, but I look at the floating-point object as an array of
unsigned char, whose values I compare to known values for several
floating-point values. It recognizes 32-bit, 64-bit, and 96-bit IEEE
(distinguishing between big-endian and little-endian), as well as
SPARC/HPPA and SGI 128-bit floating-point formats, plus 64-bit and
128-bit Cray floating-point. (Since I don't do exhaustive testing, a
false positive is always a remote possibility.)
 
K

Keith Thompson

CBFalconer said:
It means the programmer is incompetent, and possibly also
incontinent. The last statement is meaningless, and invokes
undefined behaviour.

It certainly invokes undefined behavior, but it's not meaningless.
Its meaning is to examine the value of f1 as if it were of type
unsigned long rather than float. There are numerous ways it can go
wrong, but it *can* do just what the author probably intended it to
do. (Which is, in a very real sense, worse than being completely
meaningless or always causing a trap.)
 
C

cheesiong

I don't think that's the most likely explanation. I can easily
imagine a programmer not knowing whether a cast is necessary when
assigning a float value to an unsigned long object, but the use of
pointer casts tells me that the programmer was deliberately trying to
examine the representation of f1 as if it were of type unsigned long.

In some contexts, that might even be a reasonable thing to do, though
it's not necessarily the best way to do it, because ...

what is the alternative?
From the code, how can we tell what is the l1? Does l1 store the
address of f1?

Could you tell me more about the undefined behavior?

thanks.
 
C

CBFalconer

.... snip ...

Could you tell me more about the undefined behavior?

Yes. It is undefined. Any behaviour is allowed. This includes
insulting Mohammed, starting WWIII, global warming, species
extinction, nasal expectoration of demons, etc. Other restrictions
may apply, but those are beyond the scope of the C language.
 
I

Ian Collins

what is the alternative?

That depends what the programmer intended.
address of f1?
No, it stores the bit pattern stored at the address of f1.
Could you tell me more about the undefined behavior?
Consider the case where float and unsigned long are different sizes, or
have differing alignment rules.

Please trim stuff you aren't responding to.
 
A

Army1987

Could you tell me more about the undefined behavior?

thanks.
When the Standard says a behaviour is undefined, the compiled program is
allowed to do *anything*, and *whatever* it does (even if it were formatting
your hard disk) will not make the compiler non-conformant.
Usually it won't format your hard disk, and it will either report an error
or do something reasonable (maybe even including "exactly what you meant to
do"). I find hard to imagine i = ++i; doing something else than increasing i
or complaining (whereas i = i++; is more ambiguous: increase i by one and
restore it to its old value, or assign it to itself and then increase it by
one?), but you should NOT rely on this if you want your program to be
portable.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top