Search code examples
c++stlbinaryifstreamfile-read

C++, weird behavior while reading binary ifstream


For my first question here, I'd like to talk about reading binary files in C++; I'm recoding an ID3 tag library.

I'm parsing the header which is a binary file, the first 10bytes are as follow:

ID3    = 3 bytes = constant identifier
0xXXXX = 2 bytes = version (MSB: major version, LSB: minor. eg: 0x0301 = v3.1)
0xXX   = 1 byte  = some flags
4*0xXX = 4 bytes = size

here's the piece of code to process that :

char          id[4];
uint16_t      version;
uint8_t       flags;
uint32_t      size;
std::ifstream _stream;

_stream = std::ifstream(_filename, std::fstream::binary);

_stream.read(id, 3);
id[3] = 0;
// process id
_stream.read((char *)&version, 2);
// process version
_stream.read((char *)&flags, 1);
// process flags
_stream.read((char* )&size, 4);
// process flags
_stream.close();

everything works fine except for version. lets say it's v3.0 (0x0300), the value set in version is 0x03, I would understand this behavior in text mode as it would consider 0x00 as end of string but here I'm reading in binary. And use numeric formats.

Other strange thing, if I process it in 2 times I can make it work, eg :

uint16_t version = 0;
char     buff;

 _stream.read(&buff, 1);
version = (buff << 8);
 _stream.read(&buff, 1);
version |= buff;

In this case the value of version is 0x0300.

Do you have any idea why the first method doesn't work properly? Am I doing something wrong ?

Anyways, thanks for your help,

Cheers !


Solution

  • The version field consists not of an unsigned short but of two unsigned bytes (major version, minor version). You should read the two version numbers separately to not getting mangled up in endianess problems.

    Endianess is platform-specific. If you insist on reading a single short that combines major and minor version, you could work around it. But in the end you write less clean and understandable code to solve a problem you created yourself.