### Thread: Printing a float as a hex number

1. No Profile Picture
Registered User
Devshed Newbie (0 - 499 posts)

Join Date
Jul 2008
Posts
5
Rep Power
0

#### Printing a float as a hex number

hello all

If a user enters a floatint point number like 10.1, I want to print out the hex number in floating point. The %X specifer allows for an int to be printed as a hex number and I heard you could do the samething with floating point numbers with casting and pointers but I can't seem to figure it out. Anyone have any ideas? Thanks
2. Convert the whole number and the fraction to hex separately, then recombine.

If you mean "express the binary pattern of the floating point representation in hex digits", that's a different story.
3. No Profile Picture
Registered User
Devshed Newbie (0 - 499 posts)

Join Date
Jul 2008
Posts
5
Rep Power
0
Originally Posted by sizablegrin
Convert the whole number and the fraction to hex separately, then recombine.

If you mean "express the binary pattern of the floating point representation in hex digits", that's a different story.
I mean if 10.1 is entered the floating point Hex number would be 4121999A.
4. No Profile Picture
Contributing User
Devshed Intermediate (1500 - 1999 posts)

Join Date
Feb 2004
Location
San Francisco Bay
Posts
1,939
Rep Power
1313
So something like this?
Code:
```#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
float a = 10.1;

printf("%X\n", *(int *)&a);

return 0;
}```

• clifford agrees : I did not ignore your post, I just took several hours typing mine!
5. No Profile Picture
Registered User
Devshed Newbie (0 - 499 posts)

Join Date
Jul 2008
Posts
5
Rep Power
0
Originally Posted by Lux Perpetua
So something like this?
Code:
```#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
float a = 10.1;

printf("%X\n", *(int *)&a);

return 0;
}```
YES!!! Thank you that is what I was looking for! Thank you.

• clifford agrees : It probably is, but beware of the circumstances in which it won't work (see below)
6. If you simply cast a float to an integer type it performs a conversion that modifies the bit pattern, which defeats the purpose. So the trick is to take the address of the float, cast the pointer to an integer pointer (which has no effect on the bit pattern of the data), and then dereference it so that the data is interpreted as an integer but witout changing the bit pattern.

You do have to be careful however to ensure that the floating point type and the integer type have the same bit-width. Doing that portably requires some thought, but basically, if we assume that both float and long are both the same width, which is generally true on the most commonly used platforms, then:

Code:
```float f = 10.1f ;
printf( "0x%8.8XL\n", *((long*)&f) ) ;```
However, to do that with a double, requires that your compiler support a 64bit integer type, which is not a given. Moreover printing a long double may prove difficult as there may not be an integer type of the same width.

A more flexible method is to take the address of the FP value, cast it to a char* and iterate through it as a char array using the size of the FP type as a limit and outputting each character as a hex digit pair. This may display in a different byte order than the previous method depending on your processor, but you could choose to display from high to low address or vice versa. In the end it does not really matter, so long as you know what you are looking at. IEEE754 does not actually specify a byte order in any case.

The char array method is an ideal application for a C++ template function so that it will handle any FP type. In fact it will allow you to display a hex dump of any type, including structures and classes.

Example:
C++ Code:
```
#include <string>
#include <sstream>
#include <iomanip>
#include <iostream>

bool isLittleEndian()
{
static bool little_endian ;
static bool endian_checked = false ;
// runtime endianness check (once only)
if( !endian_checked )
{
const short endian_test_pattern = 0x00ff ;
little_endian = *(reinterpret_cast<const char*>(&endian_test_pattern)) == '\xff' ;
endian_checked = true ;
}

return little_endian ;
}

template <class T>
std::string type_to_hex( const T arg )
{
std::ostringstream hexstr ;
const char* addr = reinterpret_cast<const char*>(&arg) ;

hexstr << "0x" ;
hexstr << std::setw(2) << std::setprecision(2) << std::setfill('0') << std::hex ;

if( isLittleEndian() )
{
for( int b = sizeof(arg) - 1; b >= 0; b-- )
{
hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;
}
}
else
{
for( int b = 0; b < sizeof(arg); b++ )
{
hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;
}
}
return hexstr.str() ;
}

using std::cout ;
using std::endl ;
int main()
{
const int i = 123 ;
const float f = 0.123f ;
const double d = 0.123 ;
const long double ld = 0.123L ;
const struct{ int x; int y; } s = { 123, 321 } ;

cout << "i:  " << type_to_hex( i ) << endl ;
cout << "f:  " << type_to_hex( f ) << endl ;
cout << "d:  " << type_to_hex( d ) << endl ;
cout << "ld: " << type_to_hex( ld ) << endl ;
cout << "s:  " << type_to_hex( s ) << endl ;

cout << "f using cast method: 0x" << std::hex << *((int*)&f) << endl ;
}```

In Win32 using VC++ 2008 this outputs:

Code:
```i:  0x00007b
f:  0x3dfbe76d
d:  0x3fbf7ced916872b0
ld: 0x3fbf7ced916872b0
s:  0x0001410007b
f using cast method: 0x3dfbe76d```
Clifford

• xlordt agrees : Well said.. I actually learned something new :P
Last edited by clifford; November 1st, 2008 at 02:30 PM. Reason: endian check in a spearate function
7. No Profile Picture
Registered User
Devshed Newbie (0 - 499 posts)

Join Date
Jul 2008
Posts
5
Rep Power
0
Originally Posted by clifford
If you simply cast a float to an integer type it performs a conversion that modifies the bit pattern, which defeats the purpose. So the trick is to take the address of the float, cast the pointer to an integer pointer (which has no effect on the bit pattern of the data), and then dereference it so that the data is interpreted as an integer but witout changing the bit pattern.

You do have to be careful however to ensure that the floating point type and the integer type have the same bit-width. Doing that portably requires some thought, but basically, if we assume that both float and long are both the same width, which is generally true on the most commonly used platforms, then:

Code:
```float f = 10.1f ;
printf( "0x%8.8XL\n", *((long*)&f) ) ;```
However, to do that with a double, requires that your compiler support a 64bit integer type, which is not a given. Moreover printing a long double may prove difficult as there may not be an integer type of the same width.

A more flexible method is to take the address of the FP value, cast it to a char* and iterate through it as a char array using the size of the FP type as a limit and outputting each character as a hex digit pair. This may display in a different byte order than the previous method depending on your processor, but you could choose to display from high to low address or vice versa. In the end it does not really matter, so long as you know what you are looking at. IEEE754 does not actually specify a byte order in any case.

The char array method is an ideal application for a C++ template function so that it will handle any FP type. In fact it will allow you to display a hex dump of any type, including structures and classes.

Example:
C++ Code:
```
#include <string>
#include <sstream>
#include <iomanip>
#include <iostream>

bool isLittleEndian()
{
static bool little_endian ;
static bool endian_checked = false ;
// runtime endianness check (once only)
if( !endian_checked )
{
const short endian_test_pattern = 0x00ff ;
little_endian = *(reinterpret_cast<const char*>(&endian_test_pattern)) == '\xff' ;
endian_checked = true ;
}

return little_endian ;
}

template <class T>
std::string type_to_hex( const T arg )
{
std::ostringstream hexstr ;
const char* addr = reinterpret_cast<const char*>(&arg) ;

hexstr << "0x" ;
hexstr << std::setw(2) << std::setprecision(2) << std::setfill('0') << std::hex ;

if( isLittleEndian() )
{
for( int b = sizeof(arg) - 1; b >= 0; b-- )
{
hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;
}
}
else
{
for( int b = 0; b < sizeof(arg); b++ )
{
hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;
}
}
return hexstr.str() ;
}

using std::cout ;
using std::endl ;
int main()
{
const int i = 123 ;
const float f = 0.123f ;
const double d = 0.123 ;
const long double ld = 0.123L ;
const struct{ int x; int y; } s = { 123, 321 } ;

cout << "i:  " << type_to_hex( i ) << endl ;
cout << "f:  " << type_to_hex( f ) << endl ;
cout << "d:  " << type_to_hex( d ) << endl ;
cout << "ld: " << type_to_hex( ld ) << endl ;
cout << "s:  " << type_to_hex( s ) << endl ;

cout << "f using cast method: 0x" << std::hex << *((int*)&f) << endl ;
}```

In Win32 using VC++ 2008 this outputs:

Code:
```i:  0x00007b
f:  0x3dfbe76d
d:  0x3fbf7ced916872b0
ld: 0x3fbf7ced916872b0
s:  0x0001410007b
f using cast method: 0x3dfbe76d```
Clifford
Wow thank you clifford. I was wondering how the convertion worked. Thanks for the post you showed me some interesting things. Thanks again :thumbs:
8. Originally Posted by kenshinofkin
Wow thank you clifford.
You are welcome, but there really s no need to re-quote the entire previous post! It is already there for all to see. Quoting is intended for making reference to out-of-order posts or particular points to make it clear what you are referring to. If you are merely referring to the previous post in its entirity, then no quote is needed.

My scroll wheel hurts! ;)