std::istream::tellg vs eofbit flag

M

mathieu

Hi,

I'd like to check if my understanding of the standard is correct. Is the following program supposed to work ?

$ cat file.cxx
#include <cassert>
#include <fstream>
#include <sstream>

int main ()
{
std::ifstream ifs (__FILE__, std::ios::binary);
std::stringstream ss;

assert (0 == ifs.tellg ());

ifs >> ss.rdbuf ();

assert (ifs.eofbit == ifs.rdstate ());
assert (ifs.eof());
assert (-1 != ifs.tellg ()); // works with g++ 4.4

return 0;
}

I am getting different results using either g++ 4.4 or g++ 4.7.

Thanks.
 
V

Victor Bazarov

I'd like to check if my understanding of the standard is correct. Is the following program supposed to work ?

$ cat file.cxx
#include <cassert>
#include <fstream>
#include <sstream>

int main ()
{
std::ifstream ifs (__FILE__, std::ios::binary);

The macro __FILE__ does not necessarily expand into a valid file name in
the environment where the resulting binary is going to run, you realize
that, yes?
std::stringstream ss;

assert (0 == ifs.tellg ());

ifs >> ss.rdbuf ();

assert (ifs.eofbit == ifs.rdstate ());
assert (ifs.eof());
assert (-1 != ifs.tellg ()); // works with g++ 4.4

return 0;
}

I am getting different results using either g++ 4.4 or g++ 4.7.

Different in what way?

'tellg' returns pos_type(-1) to indicate *failure*. Are you sure
reading out the entire file is supposed to set the failbit? If you try
*reading* after the 'eof' condition has been achieved, *then* you get a
failure (because that input operation fails), and *then* 'tellg' should
return pos_type(-1). That's my take on it.

V
 
M

mathieu

The macro __FILE__ does not necessarily expand into a valid file name in

the environment where the resulting binary is going to run, you realize

that, yes?








Different in what way?



'tellg' returns pos_type(-1) to indicate *failure*. Are you sure

reading out the entire file is supposed to set the failbit? If you try

*reading* after the 'eof' condition has been achieved, *then* you get a

failure (because that input operation fails), and *then* 'tellg' should

return pos_type(-1). That's my take on it.

Not according to cplusplus.com:

http://www.cplusplus.com/reference/istream/istream/tellg/

"Notice that the function will work even if the eofbit flag is set before the call."

Hence, my question...
 
V

Victor Bazarov

....and you didn't answer this question.
Not according to cplusplus.com:

What is the meaning of "not" in your statement here? Somehow
cplusplus.com has something to say about /my take on/ how tellg
operates? Or is there something in its explanation that contradicts
what I wrote on how tellg works (or supposed to, anyway)?
http://www.cplusplus.com/reference/istream/istream/tellg/

"Notice that the function will work even if the eofbit flag is set before the call."

Yes. Do you realize that 'eofbit' and 'badbit' are not the same? When
we say "failure", it means the 'badbit' is set. 'eofbit' is only set
when the reading *reaches* the end of the stream.
Hence, my question...

So, to answer your question, yes, the program is supposed to work. If
it does not (it would be nice to see your explanation of what "does not"
is here), then it is likely due to a bug in the implementation of the
standard I/O library that you're using. <shrug>

The function 'tellg' is supposed to return rdbuf()->pubseekoff(0, cur,
in), if the failbit is *not* set (i.e. fail() == false). If the failbit
*is* set (indicating the failure of the last operation) *then* it
returns -1.

Instead of asserting on 'tellg', see if you get the 'fail()' to return
'false' in that case (isn't that what you suppose should hold in your
situation?) and then we could start trying to understand what *exactly*
is going wrong in one of your programs.

V
 
J

James Kanze

On 7/26/2013 2:37 AM, mathieu wrote:

I'm not sure that the two asserts above are guaranteed to pass
(although it's hard to imagine an implementation where they
didn't).

The requirements have changed between C++03 and C++11. C++03
requires std::istream::seekg to fail if eofbit is set. C++11
says that eofbit will first be reset, before attempting the
seek. (I believe that the behavior specified by C++11 was what
was wanted from the beginning, but C++03 definitly says that
seekg should fail if eofbit is set.)

[...]
Only in C++11. The language has changed in this regard.
Yes. Do you realize that 'eofbit' and 'badbit' are not the same? When
we say "failure", it means the 'badbit' is set.

No. When we say "failure", we mean that either 'failbit' or
'badbit' are set. Most implementations of istream will never
set 'badbit'. (They should, in case there is a real hardware
read error, but they don't.)
'eofbit' is only set
when the reading *reaches* the end of the stream.

More correctly, 'eofbit' is only set when the standard says it
should be set. In general, I would expect it to be set whenever
streambuf::sgetc, streambuf::sbumpc or streambuf::snextc returns
end of file. But the standard is fairly vague about this; it
doesn't mention setting eofbit in the description of operator>>
to a streambuf. One could argue that this means that eofbit
shouldn't be set. (One could also argue that this is an
oversight. C++03 also says that this >> behaves as a formatted
input function, which means that it should skip leading
whitespace. It didn't in classical iostreams, and this has been
corrected in C++11. Perhaps not setting eofbit is a similar
oversight, which just hasn't been corrected yet.)
So, to answer your question, yes, the program is supposed to work. If
it does not (it would be nice to see your explanation of what "does not"
is here), then it is likely due to a bug in the implementation of the
standard I/O library that you're using. <shrug>

His program is based on unspecified behavior at one point, and
behavior which has changed between C++03 and C++11 at another.
My guess is that g++ 4.4 is implementing exactly what is
specified in C++03, and that g++ 4.7 is implementing the C++11
behavior, considering the change as a "correction", and so not
requiring -std=c++11 to get it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top