Reputation: 9
In the following example, how would I print out the value in u? I keep on printing out the address.
int example (float f)
{
unsigned int u = *(unsigned int*)&f;
printf("The value in u is: %u\n", u);
}
EDIT
I have something like this:
int example (float f)
{
unsigned int u = *(unsigned int*)&f;
if((u&u) && u != MASK) {
printf("The value in u is: %u\n", u);
printf("The address in u is: %u" , u);
}
}
int main ()
{
example(3);
return(EXIT_SUCCESS);
}
The problem that I have is when I try to check and print out the value of 'u'. I can't seem to get it to print out.
Upvotes: 0
Views: 1951
Reputation: 754920
This is an extension of your code that compiles and runs OK under GCC 4.7.1 on Mac OS X 10.7.5.
#include <stdio.h>
#include <inttypes.h>
static void example(float f)
{
unsigned int u = *(unsigned int*)&f;
printf("%13.6e: %10u = 0x%08X (address 0x%08" PRIXPTR ")\n",
f, u, u, (uintptr_t)&f);
}
int main(void)
{
example(+3.14159F);
example(+0.0);
example(-0.0);
example(+3.456789e24);
example( 3.456789e-24);
example(-3.456789e24);
example(-3.456789e-24);
return(0);
}
Output:
3.141590e+00: 1078530000 = 0x40490FD0 (address 0x7FFF5FD3754C)
0.000000e+00: 0 = 0x00000000 (address 0x7FFF5FD3754C)
-0.000000e+00: 2147483648 = 0x80000000 (address 0x7FFF5FD3754C)
3.456789e+24: 1748435002 = 0x6837003A (address 0x7FFF5FD3754C)
3.456789e-24: 411417185 = 0x1885BA61 (address 0x7FFF5FD3754C)
-3.456789e+24: 3895918650 = 0xE837003A (address 0x7FFF5FD3754C)
-3.456789e-24: 2558900833 = 0x9885BA61 (address 0x7FFF5FD3754C)
As you can see, I use a 64-bit machine. You can see in the hex that the sign bit is in the most significant byte; less obvious is that the exponent is in the next 8 bits, and the mantissa in the remaining 23 bits.
Your code is very close to what I'm demonstrating — once the typos were fixed. Your code using MASK
is mysterious since you don't show what MASK
is. However, it should print the information for almost any float value except positive zero (because then u&u
evaluates to false) or the one specific float value that has a bit pattern that matches MASK
.
For my code, the compiler warns:
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition x.c -o x
x.c: In function ‘example’:
x.c:6:5: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
$
Here is another extension, and more sample output:
#include <stdio.h>
#include <inttypes.h>
static void example(float f)
{
unsigned int u = *(unsigned int*)&f;
unsigned int s = u >> 31;
unsigned int e = (u >> 23) & 0xFF;
unsigned int m = (u >> 16) & 0x7F;
printf("%13.6e: %10u = 0x%08X (s=%u, e=x%02X, m=0x%02X) (0x%08" PRIXPTR ")\n",
f, u, u, s, e, m, (uintptr_t)&f);
}
int main(void)
{
example(+3.14159F);
example(+0.0);
example(-0.0);
example(+1.0);
example(-1.0);
example(+2.0);
example(-2.0);
example(+3.0);
example(-3.0);
example(+4.0);
example(-4.0);
example(+5.0);
example(-5.0);
example(+3.456789e24);
example( 3.456789e-24);
example(-3.456789e24);
example(-3.456789e-24);
return(0);
}
Output:
3.141590e+00: 1078530000 = 0x40490FD0 (s=0, e=x80, m=0x49) (0x7FFF6112754C)
0.000000e+00: 0 = 0x00000000 (s=0, e=x00, m=0x00) (0x7FFF6112754C)
-0.000000e+00: 2147483648 = 0x80000000 (s=1, e=x00, m=0x00) (0x7FFF6112754C)
1.000000e+00: 1065353216 = 0x3F800000 (s=0, e=x7F, m=0x00) (0x7FFF6112754C)
-1.000000e+00: 3212836864 = 0xBF800000 (s=1, e=x7F, m=0x00) (0x7FFF6112754C)
2.000000e+00: 1073741824 = 0x40000000 (s=0, e=x80, m=0x00) (0x7FFF6112754C)
-2.000000e+00: 3221225472 = 0xC0000000 (s=1, e=x80, m=0x00) (0x7FFF6112754C)
3.000000e+00: 1077936128 = 0x40400000 (s=0, e=x80, m=0x40) (0x7FFF6112754C)
-3.000000e+00: 3225419776 = 0xC0400000 (s=1, e=x80, m=0x40) (0x7FFF6112754C)
4.000000e+00: 1082130432 = 0x40800000 (s=0, e=x81, m=0x00) (0x7FFF6112754C)
-4.000000e+00: 3229614080 = 0xC0800000 (s=1, e=x81, m=0x00) (0x7FFF6112754C)
5.000000e+00: 1084227584 = 0x40A00000 (s=0, e=x81, m=0x20) (0x7FFF6112754C)
-5.000000e+00: 3231711232 = 0xC0A00000 (s=1, e=x81, m=0x20) (0x7FFF6112754C)
3.456789e+24: 1748435002 = 0x6837003A (s=0, e=xD0, m=0x37) (0x7FFF6112754C)
3.456789e-24: 411417185 = 0x1885BA61 (s=0, e=x31, m=0x05) (0x7FFF6112754C)
-3.456789e+24: 3895918650 = 0xE837003A (s=1, e=xD0, m=0x37) (0x7FFF6112754C)
-3.456789e-24: 2558900833 = 0x9885BA61 (s=1, e=x31, m=0x05) (0x7FFF6112754C)
This is beginning to analyze the IEEE 754 single-pricision floating point format in some detail. The referenced Wikipedia page gives more information on why the values I used for creating s
, e
, m
are of relevance (noting that I'm working on an Intel machine and hence this is little-endian data).
Except with the 'gradual underflow' values, zeros, infinities and NaNs, the first bit of the 'real' mantissa is always a 1, so the format does not actually store that. You can see this from the values for 1, 2, 4 — contrast with 3 and 5 (each of which has only one bit set in the mantissa, even though the binary representation of 3 and 5 contains two set bits).
Upvotes: 1