VS2005 C++ Express basic_istream::get(buf, size, delim) bug

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by Terry » Thu, 05 Oct 2006 03:45:29


{ Note: this article is cross-posted to [comp.lang.c++.moderated] and
[microsoft.public.vc.language]. For follow-ups, please keep in mind
that "environment specific" is a standard clc++m rejection reason.
I.e., please keep the discussion on-topic, concerning the C++ language
and how C++ compilers implement the language. -mod }



It seems that cin.get(char*, size_t, '\n') "fails" on a blank line.
g++ has the same behavior if I strip the carriage returns from the line
ends.
I would have expected it to succeed with gcount() == 0.
I can't believe I haven't encountered this before. VS2003 C++ 7.1
behaves the same.
I guess I've been using getline(cin, str) and unknowingly avoided this.
How do I fix this code, then, without using std::string?

terry


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by Terry » Thu, 05 Oct 2006 09:40:08


*** Stops reading at the first blank line.***

<<< Copied from microsoft.public.vc.language. >>>


Thank you, Mr Tandetnik.
g++ behaves the same way.
The only reason it appeared to work was that there were carriage returns
before the newline chars.
When I stripped the \r's, g++ set failbit too.

I'm not sure why basic_istream::get() works this way.
I would have prefered reading nothing, setting Line[0] to '\0', and
cin.gcount() == 0, without setting ios::failbit.
I'll bet people smarter than I debated it for months.
Can anyone explain why ios::failbit should be set in this case?

Here's updated code that works.

#include <iostream>
#include <limits>
using namespace std;
int main() {
static char Line[1024];
for (;;) {
if (!cin.get(Line, sizeof(Line))) {
if (cin.bad() || cin.eof())
break;
cin.clear();
}
cin.ignore(numeric_limits<int>::max(), '\n');
cout << ':' << Line << endl;
}
} // main



--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by denise.kle » Thu, 05 Oct 2006 09:55:37

Hello Terry!


As it should do: if no character is stored, this should set failbit.


Why am I not surprised...?


Read 27.6.1.3/8-9: this should change your expectation.


... or you have used cin.getline(buffer, sizeof(buffer), '\n') and
unknowingly avoided this.


What do you want to achive? ... and why do you want to avoid
std::string?

Good luck, Denise


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by Alberto Ga » Thu, 05 Oct 2006 21:58:46

Terry G ha scritto:

Because, in a certain sense, the operation failed. Consider that there
is also a getline() method that has a different (perhaps less
surprising) semantic and may be more useful in this case. Here is the
same code written with getline():

// #blah blah here
int main() {
static char Line[1024];
for (;;) {
cin.getline(Line, sizeof(Line));
if (cin.bad() || cin.eof())
break;
else if(cin.fail()) {
// buffer overflow!
cin.clear();
cin.ignore(numeric_limits<int>::max(), '\n');
}
cout << ':' << Line << endl;
}
} // main

Notice how you get the chance to handle the buffer overflow condition
explicitly and you don't need to extract the terminator in the "normal"
case.

Regards,

Ganesh

--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by Hyman Rose » Fri, 06 Oct 2006 12:33:03


Yes. See 27.6.1.3/8.


Then g++ must have the input open in binary mode while VC has it open
in text mode. The latter is converting \r\n pairs to \n before the
input routines ever see them.


Use cin.getline(char*, size_t, '\n') instead. It will extract the
delimiter but won't store it, relieving you from having to call
ignore.

--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by kanz » Fri, 06 Oct 2006 22:34:35


What sense? In a certain sense, the operation failed if it
didn't read the number of characters requested, too. The most
reasonable way of interpreting the functions contract is to read
0 or more characters, up to... Saying that the contract is 1 or
more characters, up to... is only slightly more arbitrary than
saying it is 10 or more characters, up to...


Attention: getline() has different semantics. In particular, it
will set an error if it doesn't find a '\n'.




In both cases, you get the hassle of having an error set in a
case that you don't want to treat as an error.


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by kanz » Fri, 06 Oct 2006 22:34:59


Or g++ was running under Unix, and obeying Unix conventions.
(As a quality of implementation issue, with the almost
universality of remote mounted filesystems in heterogeneous
networks, I would expect libraries on both Unix and Windows
platforms to support both line termination conventions.)



That doesn't fix it, because it fails if the line is too long.


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by Alberto Ga » Sat, 07 Oct 2006 03:27:02

kanze ha scritto:


You mean: getline() will set failbit if the buffer is exhausted without
finding a '\n'. Yes, that's exactly what I want it to do ;-)


The fact that we don't want to treat it as an error in this particular
case is irrelevant. A potential buffer overflow looks terribly like an
error to me and I'd expect a general-purpose library to report it as
such. You may have a different opinion, of course.

As you surely know very well, the main problem with the iostream library
is that it has only few bits (eofbit, failbit and badbit) with which to
report every possible exceptional condition. As eofbit and badbit have a
slightly clearer semantic, that sometimes leaves on failbit the onus to
report more conditions that one would expect to.

Ganesh

--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by kanz » Sat, 07 Oct 2006 21:19:18


But that's not what he wanted to do:-).




My opinion is simple: we have two different functions, one which
considers the case an error, and another which doesn't. If you
don't want to consider it as an error, you should use the one
that doesn't.

I agree that in most cases I can think of, I'd want to treat it
as an error. If nothing else, I'd want to log the fact that
there was an anomaly. But there are exceptions: the Fortran
standard (at least the one I knew, back then) said that all
characters after column 72 were to be ignored; in a Fortran
compiler, reading into a buffer of 72 characters, and ignoring
the rest, seems perfectly valid.


I know. Anytime you don't know what to do, you set failbit:-).


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by kanz » Sat, 07 Oct 2006 21:20:35


FWIW: this is a (gratuous) change compared to the behavior in
classical IO streams (where the original posters code works as
expected). I wonder if it isn't really a mistake in the
standard, and that intent was for it to work. It certainly
makes more sense if it works.


--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
 
 

VS2005 C++ Express basic_istream::get(buf, size, delim) bug

Post by P.J. Plaug » Sun, 08 Oct 2006 09:54:01


I complained about it over a decade ago, while there was still
a chance for it to change. I was overruled.

P.J. Plauger
Dinkumware, Ltd.
http://www.yqcomputer.com/



--
[ See http://www.yqcomputer.com/ ]
[ comp.lang.c++.moderated. First time posters: Do this! ]