2

I wanted to create a single byte binary file with only one byte in it: 0x01. This is the program I wrote in C++ :

#include <iostream>
#include <fstream>
using namespace std ;

int main ( )
{
    ofstream some_file ("some_file.bin", ios::out | ios::app | ios::binary);
    some_file << 0x01 ;
    some_file.close( );
    return 0;
}

When I inspect the created file using a hex editor - I see the value 0x31 instead of 0x1. Why is that ?

shaiko
  • 159
  • 6
  • 3
    This doesn’t address the question, but you don’t need to call `some_file.close()`. The destructor will do that. – Pete Becker Dec 29 '19 at 21:44
  • Any enriching comments are most welcome - so thanks. But can you point to where the Destructor is called ? I thought a C++ Destructor must be preceded by a tilde (~)... – shaiko Dec 29 '19 at 22:14
  • 2
    @shaiko The destructor of every constructed variable of class type declared at block scope is called automatically when control flow leaves the block. Here the destructor of `some_file` is called when `main` exits. The destructor of `std::ofstream` closes the file if any is open. This behavior is an important part of the [RAII principle](https://stackoverflow.com/questions/2321511/what-is-meant-by-resource-acquisition-is-initialization-raii) of C++. – walnut Dec 29 '19 at 22:17

3 Answers3

6

0x01 is an integer literal. Integer literals are always of integer type with rank at least that of int. Therefore they cannot be of type char (or signed char/unsigned char).

In your case 0x01 will have type int.

char and its signed/unsigned variants are the only integral type for which operator<< on an std::ostream will output a single character represented by the value held in the char.

For other integral types operator<< will output the integer value formatted in decimal representation.

If you want to print the single character from its ASCII code, you need to cast 0x01 to char:

some_file << char{0x01};

or use a character literal:

some_file << '\x01';

or you can use the put method to place a single character, which takes a char parameter and will therefore cause implicit conversion of the int literal to char, which will then be printed as one character represented by the value:

some_file.put(0x01);

or

some_file.put('\x01');

Contrary to <<, put will write the character directly without change. << is affected by formatting options that can be set on the stream, e.g. there could be padding added. If you want to be absolutely sure that only the single character is printed without change, put is probably the correct choice.

walnut
  • 21,629
  • 4
  • 23
  • 59
3

You get 0x31 (49) because You're using operator<<() which is used to write formatted data. Use std::basic_ostream::put() or std::basic_ostream::write() to write data as it is.

J. Doe
  • 466
  • 3
  • 11
1

ios::binary doesn’t really mean “I’m writing a binary file”. It means “don’t do text-mode translations” which primarily means don’t write carriage-return line-feed when the program inserts \n into the stream under Windows.

Stream inserters translate numeric values into their text representation, regardless of the stream’s mode. This is referred to as “formatted output”. To write unformatted values, use std::basic_ostream::write, like this:

int value = 0x01;
some_file.write(&value, sizeof(value));
Pete Becker
  • 74,985
  • 8
  • 76
  • 165