3

I am trying to write nothing but uint32_t data to a .bin file. I start by opening up a file stream which I declare to be a binary one.

  `hartInStream.open (hartFileToWrite.c_str(), std::ifstream::binary);
   if(!hartOutStream.is_open())
        {
        printf("Something in outstream went wrong.\n");  
        }
   else 
        {
        printf("Yippy! it outstream worked!\n");  
        printf("---------Starting to read-------------\n");}`

Next, I take the data I am trying to write, in this case a uint32_t "data", print it out, and write it to the end of my file stream.

printf(" Reading %lu from HART at %d-%d-%d\n", data, (int)addr1, (int)addr2, (int)addr3 );

Lastly I append the data

hartOutStream<<data;

I know that I should be writing 0x00 0x00 0x01 0x00 (256) as the first 4 bytes but I am writing 32 35 36 which is the hex equivalent of ascii charters to 256. (using HxD file viewer)

I suspect the problem is in the << operator where it typecasts it to ascii. I've tried typecasting, the atoi() function but nothing seems to work. Does anyone know what is wrong with this?

Thanks

William Dussault
  • 375
  • 2
  • 17
  • What you could try is creating a pointer to the integer, cast it to char pointer and then print the dereferenced chars to the file. like this hartOutStream << (char*)&data << ++((char*)&data) << ++((char*)&data) << ++((char*)&data); – Pinna_be Apr 03 '14 at 16:02
  • @Pinna_be That's a good recipe for undefined behavior. – James Kanze Apr 03 '14 at 16:12
  • @JamesKanze isn't writing a binary representation of integer not a recipe for undefined behaviour on it's own? My method (although it is not a good solution at all and you're right about that) doesn't change the recipe. Writing an integer to a file in binary form is a recipe for undefined behavior in it's own, if you don't know who is going to read it (and with which endianness) That being said, the answers below actually do the same but just cleaner. – Pinna_be Apr 03 '14 at 17:20
  • @Pinna_be No. Why should it be? There are lots of protocols which use a binary format. See my post for a portable way of doing it (at least for unsigned integral types). (Actually, your method shouldn't even compile, since `((char*)&data)` is an rvalue, and `++` requires an lvalue. But if instead of `((char*)&data)` you had a `char*` lvalue, it would be undefined behavior because it modifies the same object more than once without the modifications being sequenced.) – James Kanze Apr 04 '14 at 08:16

2 Answers2

10
ofstream f;
f.open("my.bin",std::ofstream::binary);
uint32_t data=0x00000100;
f.write((char*)&data,sizeof(data));
Beowulf
  • 420
  • 2
  • 7
1

The << operators format to text. If you want a binary format, you'll have to format manually into a std::vector<char>, then write that out using std::ostream::write(). Something like:

std::vector<char> buf;
buf.push_back( (data >> 24) & 0xFF );
buf.push_back( (data >> 16) & 0xFF );
buf.push_back( (data >>  8) & 0xFF );
buf.push_back( (data      ) & 0xFF );
hartOutStream.write( buf.data(), buf.size() );

(If you are using an older C++, you might need to write &buf[0], rather than buf.data().)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Would this work: `uint32_t my_variable; hartOutStream.write((char *) &my_variable, sizeof(my_variable));` ? Your method allows for little or big endian. My method just writes it out. :-) – Thomas Matthews Apr 03 '14 at 16:28
  • a better way to get endian-independence, if you are only writing a single `uint32_t`, is the [`htonl` family of functions](http://linux.die.net/man/3/htonl). – japreiss Apr 03 '14 at 16:31
  • @japreiss And how is a non-standard function better? Especially one that can only be used in restricted circumstances. – James Kanze Apr 03 '14 at 16:33
  • My method ensures that you can reread it later. Just writing it out doesn't. – James Kanze Apr 03 '14 at 16:34
  • Because it doesn't use heap memory... but you could just replace the `std::vector buf` with `char buf[4]` instead. Point taken. – japreiss Apr 03 '14 at 17:04