• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Reading Float32 from a file in C++

Status
Not open for further replies.
Level 19
Joined
Aug 8, 2007
Messages
2,765
Logically, I assumed that the first two bytes would be the decimal portion and the last two bytes would be the integral portion, but it seems thats not the case because floats can get up to E38 so I'll ask here

How do i convert a byte sequence like

FF F3 3B 3A

into a float32?

2E/ I can cast a float into a char*, but not a char* into a float...
 
Last edited:
If you're using something like std::ifstream, you could do it like this:
C++:
    // assume 'in' refers to an open binary input stream
    // assume bytesToRead refers to the number of bytes to read
    // bytesToRead can be sizeof(float)

    float flo = 0; // write to this float variable

    in.read((char*)(&flo), bytesToRead);

On success, flo should contain the value of the 4 bytes of hex as a float.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
You cannot convert them. Floats are platform specific as such you need to know the float specification that was used in the file to be able to convert them. IEEE floats are most common, especially with files due to their standard nature, but not all floats are IEEE as their strict format is too slow for many practical purposes (will not find them in cache files). Most floats generally use the same bit partitioning with only how computations are done changing, but may or may not represent the same value (IEEE floats have special values).


2E/ I can cast a float into a char*, but not a char* into a float...
You cannot cast a float to a char* without it becoming total gibberish. Same goes for a char* into a float. A pointer is a special sized type that is based on the memory address size. Since systems like Windows are at least 32bit all pointers are at least 32bit and as such you can cast a float to a char* but the result will be total nonsense and can change from run to run.

The idea is you do not cast the float to a char*, but the float* (float reference) of the float to a char*. This changes how the pointer is interpreted so instead of being interpreted as a float, it is interpreted as chars when dereferenced (internally the pointer is unchanged). This works the other way and does exactly what you want (I think?!).

Get a buffer, fill it with bytes representing a float then convert the char buffer (which is char*) into a float buffer (float*). You can then dereference it to get a float. Sounds computationally expensive due to all the conversions but in reality all that is free and corresponds to no compiled instructions (only purpose is to help compiler and programmer).

Some times this will work but not always. Depends entirely on what the platform uses for a float.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Actually i found a more elegant solution to do it (was using the wrong ifstream functions) but now i have another problem with ifstream... heh...

C++:
// reading an entire binary file
#include <iostream>
#include <fstream>
#include "BinaryReader.cpp"
#include <vector>

using namespace std;

int main() {

	ifstream file("binary.txt", ios::in | ios::binary | ios::ate);
	
	if (file.is_open())
	{
		file.seekg(0,ios::beg);
		char first = 0;
		file >> first;
		cout << " pos : " << file.tellg() << "first : " << first;

	}
	else cout << "Unable to open file";
	file.close();
	char inputDelay = 0;
	cin >> inputDelay;
	return 0;
}

(the file contents of binary.txt are 61 11 11 11 11 11 11 11 11 11, which is a......... according to HxD)

this returns 'pos:1 first:a" like it should, but if i try swapping "char" for "int"

C++:
// reading an entire binary file
#include <iostream>
#include <fstream>
#include "BinaryReader.cpp"
#include <vector>

using namespace std;

int main() {

	ifstream file("binary.txt", ios::in | ios::binary | ios::ate);
	
	if (file.is_open())
	{
		file.seekg(0,ios::beg);
		int first = 0;
		file >> first;
		cout << " pos : " << file.tellg() << "first : " << first;

	}
	else cout << "Unable to open file";
	file.close();
	char inputDelay = 0;
	cin >> inputDelay;
	return 0;
}

it gives me

"pos:-1 first:0xA3333334" (it prints an integer number, but i thought the hexadecimal representation would be more helpful) (if i pass it an unsigned int, it just returns first:0)

if i try to read more ints, the pos stays at -1 and it prints the same number.

(yay, learning a new language...)
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
The >> operator for streams is used for text data as far as I remember. C++ has no elegant functions for binary data, just an uglier C++ish API for C's FILE*.
Correct me if I am wrong, I do not follow the new versions that seem to come out every second day now.

But really, fread is so much more flexible than >> in any case, I honestly don't see the point of using streams for binary data.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
The >> operator for streams is used for text data as far as I remember. C++ has no elegant functions for binary data, just an uglier C++ish API for C's FILE*.
Correct me if I am wrong, I do not follow the new versions that seem to come out every second day now.

But really, fread is so much more flexible than >> in any case, I honestly don't see the point of using streams for binary data.

hm, actually, this just goes back to P&F's answer.. (i think your right >> is used for text based data and chars are universal)

C++:
first = *((int*)readChar);

and i just read chars like i was doing before

C++:
file.read(readChar,sizeof(int))

i thought the pointer hack was printing the wrong number because the hex was 32343333 (where the bytes were 33 33 34 32) but i forgot its little endian. (Now to go back and undo all of the >> changes i made in my code :/)
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
The >> operator for streams is used for text data as far as I remember. C++ has no elegant functions for binary data, just an uglier C++ish API for C's FILE*.
Correct me if I am wrong, I do not follow the new versions that seem to come out every second day now.

But really, fread is so much more flexible than >> in any case, I honestly don't see the point of using streams for binary data.

lol second day, I bet shit like Java has updates 10x more frequently than C++ :D
 
Use this.

C++:
namespace io {
    template<typename T>
    T read(std::istream& stream) {
        T t;
        stream.read(reinterpret_cast<char*>(&t), sizeof(T));
        return t;
    }
    
    template<typename T>
    void write(std::ostream& stream, T&& t) {
        stream.write(reinterpret_cast<char*>(&t), sizeof(T));
    }
}

You fall into issues with endianness however. That can be fixed easily. Just write to your files in one common endian (Do the conversion after reading, and before writing, only if needed)

Use JSON or just regular text files because fuck you, you're not writing a media file format.

Storage costs the average user $100 per 1,000,000,000,000 bytes.
It's nothing to worry about.
 
Last edited:
Level 23
Joined
Apr 16, 2012
Messages
4,041
erm...
std::istream::write does not exist...

edit: fixed code:

C++:
namespace io {

    template<typename T>
    T read_binary(std::istream& stream) {
        T t;
        stream.read(reinterpret_cast<char*>(&t), sizeof T);
        return t;
    }

    template<typename T>
    void write_binary(std::ostream& stream, T const& binary) {
        // You might need to throw in a const_cast in here to change binary to (T&). Not sure.
        stream.write(reinterpret_cast<const char*>(&binary), sizeof T);
    }

}


also, drawback is that io::read_binary requires explicit template type
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
im not writing any files, im just reading from a .mdx to a openGL context. Also, this has been solved for a while, thanks though.
 
Status
Not open for further replies.
Top