Reputation: 1
In the below program:
union
{
int i;
float f;
} u;
Assuming 32 bit compiler, u
is allocated with 4 bytes in memory.
u.f = 3.14159f;
3.14159f
is represented using IEEE 754, in those 4 bytes.
printf("As integer: %08x\n", u.i);
What does u.i
represent here? Is IEEE 754 binary representation interpreted as 4 byte signed int
?
Upvotes: 0
Views: 2095
Reputation: 126787
Reading from i
is implementation-defined blah blah blah.
Still.
On "normal" platforms where
float
is IEEE-754 binary32 formatint
is 32 bit 2's complementfloat
and int
is the sameunion
s is well defined (C99+)(AKA any "regular" PC with a recent enough compiler)
you will get the integer whose bit pattern matches the one of your original float
, which is described e.g. here
Now, there's the sign bit that messes up stuff with the 2's complement representation of int
, so you probably want to use an unsigned
type to do this kind of experimentation. Also, memcpy
is a safer way to perform type-punning (you won't get dirty looks and discussions about the standard), so if you do something like:
float x = 1234.5678;
uint32_t x_u;
memcpy(&x_u, &x, sizeof x_u);
Now you can easily extract the various parts of the FP representation:
int sign = x_u>>31; // 0 = positive; 1 = negative
int exponent = ((x_u>>23) & 0xff; // apply -127 bias to obtain actual exponent
int mantissa = x_u & ~((unsigned(-1)<<23);
(notice that this ignores completely all the "magic" patterns - quiet and signaling NaNs and subnormal numbers come to mind)
Upvotes: 3
Reputation: 75555
According to this answer, reading from any element of the union other than the last one written is either undefined behavior or implementation defined behavior depending on the version of the standard.
If you want to examine the binary representation of 3.14159f
, you can do so by casting the address of a float
and then dereferencing.
#include <stdint.h>
#include <stdio.h>
int main(){
float f = 3.14159f;
printf("%x\n", *(uint32_t*) &f);
}
The output of this program is 40490fd0
, which matches with the result given by this page.
As interjay correctly pointed out, the technique I present above violates the strict aliasing rule. To make the above code work correctly, one must pass the flag -fno-strict-aliasing
to gcc
or the equivalent flag to disable optimizations based on strict aliasing on other compilers.
Another way of viewing the bytes which does not violate strict aliasing and does not require the flag is using a char *
instead.
unsigned char* cp = (unsigned char*) &f;
printf("%02x%02x%02x%02x\n",cp[0],cp[1],cp[2],cp[3]);
Note that on little endian architectures such as x86, this will produce bytes in the opposite order as the first suggestion.
Upvotes: 0