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 02:05:35


Is this a compiler bug? Does your C++ compiler produce the same results?
terry

=========================================================
File: try_get.cpp
=========================================================
#include <iostream>
#include <limits>

int main() {
static char Line[1024];
while (std::cin.get(Line, sizeof(Line), '\n')) {
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
std::cout << ':' << Line << std::endl;
}
} // main
=========================================================
Compiling: cl -EHsc try_get.cpp
Running: try_get < try_get.cpp
yields:
=========================================================
:#include <iostream>
:#include <limits>
=========================================================
Compiling: g++ try_get.cpp
Running: a < try_get.cpp
Yields:
=========================================================
:#include <iostream>
:#include <limits>
:
:int main() {
: static char Line[1024];
: while (std::cin.get(Line, sizeof(Line), '\n')) {
: std::cin.ignore(std::numeric_limits<int>::max(), '\n');
: std::cout << ':' << Line << std::endl;
: }
:} // main
 
 
 

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 Igor Tande » Thu, 05 Oct 2006 03:50:54


g++ is wrong. C++ standard about basic_istream::get : "27.6.1.3/8 If the
function stores no characters, it calls setstate(failbit)." Once failbit
is set, the stream object would evaluate to false in boolean context.
That's why the loop should terminate on an empty line.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
 
 
 

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

Post by Terry » Thu, 05 Oct 2006 04:54:02

>> Terry G wrote

Below, cin.get() sets failbit on a blank line, per the standard (see below).






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.

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
 
 
 

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 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: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! ]