1

I'm writing four ints (a=1, b=2, c=3, d=4) to a binary file in C++ with fstream, but when I try to read them back, they do not match.

First of all, the written binary is 4 bytes long. Shouldn't it be 16 bytes (4 ints x 4 bytes/int)? When I read, I get the weird result 1234 2 3 4 if I do not zero-initialize the variables in the read function, or 1234 0 0 0 if I do.

Also, how is the result being modified by the zero-initialization? I know not initializating can lead to nasty results, but how exactly are the variables in read() getting those values that match the ones in write()?

#include <fstream>
#include <iostream>

void write()
{
    std::ofstream output( "test.bin", std::fstream::binary | std::fstream::out);
    int a=1, b=2, c=3, d=4;
    output << a << b << c << d;
    output.close();
}

void read()
{
    std::ifstream input( "test.bin", std::fstream::binary | std::fstream::in);
    int a, b, c, d;
    // int a=0, b=0, c=0, d=0;
    input >> a >> b >> c >> d;
    input.close();

    std::cout << a << " " << b << " " << c << " " << d << " " << std::endl;
}

int main()
{
    write();
    read(); // Shows 1234 2 3 4 or 1234 0 0 0
}
10
  • 1
    operator<<(..., int) is a FormattedOutputFunction. It's formatting the integers as strings with no separation between them. Concatenated strings of digits look indistinguishable from a single integer (1234) when you read it back. You can trivially confirm this by looking at your own file. Use hexdump or similar to be safe if you expect it to be an un-printable binary file. Commented Dec 1, 2020 at 16:30
  • 1
    You are writing "1234", and then reading 1234 into a. The values of b, c, d are basically random, that's why the zero init changes them. Commented Dec 1, 2020 at 16:30
  • 1
    I was under the impression that for binary read/write, you want to use the stream's .read/.write functions. Commented Dec 1, 2020 at 16:41
  • 1
    @Cedric since c++11 0 is assigned in case extraction failed. In any case there is nothing "random" Commented Dec 1, 2020 at 16:41
  • 1
    @largest_prime_is_463035818 What makes you say that? In case of assignment (even in C++11 and later), I'd say nothing is passed to the variable since the stream failed before the extraction, meaning it retains it's previous value. In this example, they are clearly not 0 since the values are 1, 2, 3. I assume they just happen to fall into the same memory as before, i.e. random. Commented Dec 1, 2020 at 17:25

1 Answer 1

3
output << a << b << c << d;

is using the operator<< stream insertion operator, which is for formatted output. All four integers are being formatted as strings, and output with no delimiter between them.

You can trivially see this by actually looking at your own file (use hexdump or similar if you expect the file to contain non-printable binary values). It contains the string 1234, doesn't it?

You want unformatted output, meaning you don't want the stream to format your integers as strings. This is done by calling write instead (and read instead of operator>>).

Output:

output.write(reinterpret_cast<char *>(&a), sizeof(a));
output.write(reinterpret_cast<char *>(&b), sizeof(b));
// etc.

Input:

input.read(reinterpret_cast<char *>(&a), sizeof(a));

Your perhaps expected the std::fstream::binary openmode to prevent stream insertion formatting your integers as strings, but this is not correct: binary mode only controls newline behaviour. The << and >> operators are always for formatted I/O.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.