0

I've been trying to get my head around the iostreams library by boost.

But i cant really fully grasp the concepts.

Say i have the following class:

Pseudocode: The below code is only to illustrate the problem.

Edit: removed the read code because it removed focus on the real problem.

class my_source {
public:
    my_source():value(0x1234) {}
    typedef char        char_type;
    typedef source_tag  category;

    std::streamsize read(char* s, std::streamsize n)
    {
      ... read into "s" ...
    }
private:
    /* Other members */
};

Now say i want to stream the this to an int.

What do i need to do ? I've tried the following

boost::iostreams::stream<my_source> stream;
stream.open(my_source());

int i = 0;
stream >> i;
// stream.fail() == true; <-- ??

This results in a fail, (failbit is set)

While the following works fine.

boost::iostreams::stream<my_source> stream;
stream.open(my_source());

char i[4];
stream >> i;    
// stream.fail() == false;

Could someone explain to me why this is happening ? Is this because i've set the char_type char ?

I cant really find a good explenation anywhere. I've been trying to read the documentation but i cant find the defined behavior for char_type if this is the problem. While when im using stringstreams i can read into a int without doing anything special.

So if anyone has any insight please enlighten me.

2 Answers2

0

All iostreams are textual streams, so this will take the bytewise representation of 0x1234, interpret it as text and try to parse it as integer.

By the way

std::streamsize read(char* s, std::streamsize n)
{
  int size = sizeof(int);
  memcpy(s, &value, 4);
  return size;
}

This has the potential for a buffer overflow if n < 4. Also, you write four bytes and then return the size of an int. memcpy(s, &value, sizeof value); will do the job, a simple return sizeof value; will do the rest.

SteveL
  • 1,811
  • 1
  • 13
  • 23
Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
  • @SteveL I understand that, but it dosnt work passing it to a integer, thats the whole problem. The code you see above is just a simple representation of the problem im having passing a stream to a int. I know and understand all overflow problems. But i dont really get why reading it to an int results in a fail bit, but reading the same data to a same sized structure like a char[4] works. – user2010820 Apr 24 '13 at 20:33
  • Assuming a little-endian system with ASCII encoding, the four-byte integer 0x1234 on will be the character sequence {4, DC2, NUL, NUL}. What integer do you expect to get from this? The '4' could be parsed as a text and even as a number, but the device control and the NULs just don't make sense in a text string. If you are using this to read a sequence of characters, their actual value doesn't make any difference, so it works. Even there, I would expect buffer overflows though in above code. If you want to read raw bytes with iostreams look at the read() function, not `>>`. – Ulrich Eckhardt Apr 25 '13 at 05:46
  • The above code is just to illustrate the problem. My question is why is reading the stream into an int results in a stream.fail() == true. While reading a stream into a char[4] is ok. – user2010820 Apr 25 '13 at 05:56
  • Is "abcd" four characters? Yes. Is it an integer? No. That is the difference! – Ulrich Eckhardt Apr 25 '13 at 16:35
  • the chars "abcd" are just a representation of 4 bytes in memory, if i like i can cpy them into a int. the underlaying stream cant possibly know if the byte stream its reading is originally an int or a sequence of chars. so my question still remains, what do i need to do to make it read the data into a int. from my pov i would say that if i pass a int to a >> operator it would look at the size of the structure and copy the right amount of data into to it. but apperantly this is not what is done. and i would like to understand why. – user2010820 Apr 25 '13 at 20:07
  • See my initial answer. The >> on streams expects the source to be a text, it doesn't work as you expect it to. Yes, this text is stored in bytes, but not all bytes are text. Your bytes are not text. The bytes representing an int in memory are generally not text. In particular, even if they can be interpreted as text, that text does not represent the number. If this still isn't clear, write an int to a file using fstream and << and then look at the file content with a hex editor. – Ulrich Eckhardt Apr 25 '13 at 20:47
0

boost::iostreams::stream constructor without arguments does nothing and in result stream is not open. You need to add fake argument to my_source constructor.

class my_source {
public:
    my_source(int fake) : value(0x1234) {}
...

boost::iostreams::stream<my_source> stream(0);
Red User
  • 429
  • 3
  • 9