Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

file stream tellg/tellp and gcc-4.6 is this a bug?

Tags:

c++

gcc

iostream

This code:

#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>

int main()
{   
    std::remove("test.txt");
    std::fstream f("test.txt",std::ios::in | std::ios::out | std::ios::binary | std::ios::trunc);
    std::cout << f.good() << std::endl;
    f<<"test"<< std::flush;
    std::cout << f.tellg() << " " << f.tellp() << std::endl;
    f.seekg(0);
    std::string s;
    f>>s;
    std::cout << f.tellg() << " " << f.tellp() << std::endl;
}   

Gives following output in gcc-4.4.5

1
4 4
4 4

i.e. both tellg and tellp returned expected stream position 4.

While gcc-4.6.0

Gives:

1
4 4
-1 4

Where can I find a reference to tell:

  1. 1st case is correct (bug in gcc-4.6)
  2. 2nd case is correct (bug in gcc < gcc-4.6)
  3. Both case are correct the behavior is undefined
like image 267
Artyom Avatar asked Jul 01 '11 20:07

Artyom


2 Answers

Ok, it is not a bug, even it seems that it is required behavior:

According to C++ 2003 standard:

  • tellg(): (27.6.1.3)

    After constructing a sentry object, if fail() != false, returns pos_type(-1) to indicate failure. Otherwise, returns rdbuf()->pubseekoff(0, cur, in).

  • sentry (27.6.1.1.2):

    if noskipws is zero and is.flags() & ios_base::skipws is nonzero, the func- tion extracts and discards each character as long as the next available input character c is a whitespace character. If is.rdbuf()->sbumpc() or is.rdbuf()->sgetc() returns traits::eof(), the function calls setstate(failbit | eofbit) (which may throw ios_base::failure).

So basically

  • tellg() creates sentry object:
  • sentry extracts white space characters and should set failbit after getting to eof.
  • tellg() sees failbit should return eof() (-1)

So gcc-4.6 seems to behave correctly...

like image 165
Artyom Avatar answered Oct 10 '22 13:10

Artyom


Ok, separate from the version analysis, which I'll leave for good measure, here is the answer:

PR/26211

I'll try to find source, but this thread discusses whether the documentation needs to be updated due to this change. It is therefore, a documented change :)

Edit Only found this: libstdc++/26211 (again) + N3168

From this page: http://gcc.gnu.org/ml/libstdc++/2011-04/msg00026.html

Hey, all.

I recently started using gcc-4.6.0 and it seems that the behaviour of std::istream::tellg() has changed when (just) the eofbit is set. I managed to track this down to PR/26211, and I'm not debating the changes.

It took me a while to figure out what was wrong because the doxygen for tellg() says:

If fail() is not false, returns pos_type(-1) to indicate
failure. Otherwise returns rdbuf()->pubseekoff(0,cur,in).

That's almost word for word what Langer and Kreft says, so I'm presuming DR60's change to 27.6.1.3 paragraph 37 has lead to this change in libstdc++ behaviour.

Should the libstdc++ doxygen be updated to say something about the fact that calling tellg()when eof() will also return pos_type(-1) (because of the fact that it constructs a sentry)? Are there other functions that also should have updated documentation as a result of DR60?

like image 37
sehe Avatar answered Oct 10 '22 11:10

sehe