Why the eof is never recognized?

Mar 20, 2013 at 10:22am
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>

using namespace std;

struct Point
{
	double x, y;

	Point(double ix, double ypsilon)
		: x(ix), y(ypsilon) {}
	Point () {}
};

ostream& operator<< (ostream& os, const Point& p)
{
	os << '(' << p.x << ',' << p.y << ')';
	return os;
}

istream& operator>> (istream& is, Point& p)
{
	char a, b, c;
	is >> a >> p.x >> b >> p.y >> c;
	if ( a!='(' || b!=',' || c!=')' ) {
		is.clear(ios_base::failbit);
		return is;
	}
	return is;
}

int main()
{
	vector<Point> original_points(2);

	cout << "Insert 2 points (each is a pair of double numbers, form: (x,y)\n";
	for(unsigned u = 0; u<original_points.size(); u++) {
		cin >> original_points[u];
	}

	cout << "Your Points where:\n";
	for (unsigned u=0; u<original_points.size(); u++) {
		cout << original_points[u]<< endl;
	}

        // writes to a file
	string file_name = "mydata.txt";
	ofstream ostr(file_name.c_str());
	if(!ostr) throw runtime_error ("Error by opening file \"mydata.txt\"");
	for (unsigned u=0; u<original_points.size(); u++) {
		ostr << original_points[u];
	}
	ostr.close();

        // reads from file
	ifstream istr(file_name.c_str());
	if(!istr) throw runtime_error("Error by opening file \"mydata.txt\"");
	istr.exceptions(istr.exceptions() | ios_base::badbit);

	vector<Point> processed_points;
	Point p;
	while (istr >> p) {
		processed_points.push_back(p);
		cout << "ok ";
	}  // till eof

	if (istr.eof())  cout <<"eof-flag" <<endl;

	if (istr.fail()) {
		cout <<"fail-flag" <<endl;
		istr.clear(ios_base::failbit);
		istr.unget();
		char c;
		istr.get(c);
		cout << "Wrong character:" << int(c);
		throw runtime_error("Wrong file format!");
	}

	cout << "The readed points are:\n";
	for (unsigned u=0; u<processed_points.size(); u++) {
		cout << processed_points[u];
	}
	cout << endl;

}

If data is correct entered, the program should branch into line 69, a recognition of eof flag.
Instead, it always branch into line 71, the fail flag and i have no clue whats
wrong.
Mar 20, 2013 at 10:31am
Did not read your code.

Be advised, eofbit is not set when you read the last element, instead is set after you tried and failed reading after the last element.
Mar 20, 2013 at 10:44am
Even I have had some problems with fstream, especially eof(). I guess eof() works only after you try reading from a stream after a read operation has failed.

i.e. first read failure doesn't set eof() true but second read failure sets eof() true.

I once made a program which would read contents from a binary file and display it on a screen. I used eof() to detect end of file. This resulted in the last line being displayed twice. The above explanation is the only one I have come up with.
Mar 20, 2013 at 1:58pm
Even I have had some problems with fstream, especially eof(). I guess eof() works only after you try reading from a stream after a read operation has failed.

This makes no sense -at least the eofbit should be setten after an attempt to read something behind the stream end, but for some reason it isn't be set. Also, the setting of eofbit shouldn't affect the setting of the failbit. I looked at the table in http://www.cplusplus.com/reference/ios/ios/fail/
Mar 20, 2013 at 3:30pm
After successfully reading the second point from the file, your Point's operator>> is entered for the third time.

The first read operation done inside that operator>> (is >> a) fails because the file ended, there is nothing to put into a. This sets BOTH eofbit and failbit, as most input operations do in this case.

You're then looking at the values of a, b, and c, which are undefined since you never wrote anything into them, but whatever they are, they are unlikely to be exactly '(', ',' and ')', so your if branch is entered.

Then you CLEAR eofbit with this code is.clear(ios_base::failbit); (this clears eofbit and badbit, and sets failbit)

Then your main function tests eofbit, which is not set, then it tests the failbit, which is set.
Last edited on Mar 20, 2013 at 3:31pm
Mar 20, 2013 at 4:17pm
I thank you so much, Cubbi, you made my day!
So its better if testing eofbit in Point's operator>>.
Last edited on Mar 20, 2013 at 4:18pm
Mar 20, 2013 at 5:09pm
I would just return the stream, not checking any flags, like the standard operator>> does with complex numbers in C++.

Actually, you could just reuse it, since you're using the same formatting:

1
2
3
4
5
6
7
8
9
std::istream& operator>>(std::istream& is, Point& p)
{
    std::complex<double> c;
    if(is >> c) {
        p.x = c.real();
        p.y = c.imag();
    }
    return is;
}

Last edited on Mar 20, 2013 at 5:10pm
Mar 20, 2013 at 9:04pm
Oh, what a hap! Thanks for this hint.
Now i tried the reading via your "complex" example.
Unfortunately, there is again a problem with the eofbit, i don't know whats now wrong:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
#include <complex>

using namespace std;

struct Point
{
	double x, y;
};

ostream& operator<< (ostream& os, const Point& p)
{
	complex<double> c(p.x,p.y);
	os << c;
	return os;
}

istream& operator>> (istream& is, Point& p)
{
	complex<double> c;
	if(is >> c) {
		p.x = c.real();
		p.y = c.imag();
	}
	return is;
}

int main()
{
	ifstream istr("mydata.txt");
	if(!istr) throw runtime_error("Error by opening file \"mydata.txt\"");
	istr.exceptions(istr.exceptions() | ios_base::badbit);

	vector<Point> processed_points;
	Point p;
	while (istr >> p) {
		processed_points.push_back(p);
		cout << "ok ";
	}  // till EOF

	if (istr.fail()) cout <<"fail-flag" <<endl;
	if (istr.eof())  cout <<"eof-flag"  <<endl;

	
	cout << "The readed points are:\n";
	for (unsigned u=0; u<processed_points.size(); u++)
		cout << processed_points[u];
}

Here will always set the failbit WITHOUT eofbit an there is no clear(...) in the code. Thanks for any hints.
Mar 20, 2013 at 9:23pm
On a sample input file I tried this with (holding the content "(1, 2) (3.14, -1)"), this program sets both flags as expected and prints
ok ok fail-flag
eof-flag
The readed points are:
(1,2)(3.14,-1)

What's in your file?
Mar 20, 2013 at 9:33pm
My file holds (1,2)(5,7) and the output is:
ok ok fail-flag
The readed points are:
(1,2)(5,7)


Also with your data i get no eof-flag :-/
Perhaps there is a bug in a library? I use the version 4.7 of gcc.
Last edited on Mar 20, 2013 at 9:59pm
Mar 20, 2013 at 9:59pm
Tested with gcc 4.7.2 (linux and aix), clang 3.1 (linux), xlc 11.1 (aix), sun studio 12 (solaris), everyone sets both flags. What's your compiler/platform?
Mar 20, 2013 at 10:33pm
I have here gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

So, i have checked that the code example here is truly the same as in my codefile, all is exactly the same.
Last edited on Mar 20, 2013 at 10:46pm
Mar 21, 2013 at 8:57pm
Must be a bug in one of my librarys.
I could it only reproduce with complex numbers (all forms)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <complex>
#include <iostream>

using namespace std;

int main()
{
	complex <bool> c;

	// end with CTRL-D or CTRL-Z
	while (cin >>c) cout <<"new number: " <<c <<endl;

	if (cin.eof ()) cout <<"eofbit set ";
	if (cin.fail()) cout <<"failbit set";
}
Mar 21, 2013 at 9:06pm
huh? complex<bool> doesn't exist (it's unspecified behavior to use one).
Mar 21, 2013 at 9:18pm
Oh, i didn'd know this. My compiler hadn't given me a warning. I also had tested complex numbers of double, long double, int, unsigned and float.
Topic archived. No new replies allowed.