Bug? ifstream::tellg() scheint leseposition zu ändern
-
Das was ihr da präsentiert habe ich doch schon längst als kontrolle gemacht.
Da passiert bei mir auch nichts, nur wenn ich die aktuelle Position der variable zuweise.
Das ist kein Bug von meiner Seite aus wiel ich überhaupt nichts mit der variable pos mache.
-
Kingcools2 schrieb:
Das ist kein Bug von meiner Seite aus
Doch. Aber ohne genauen Code keine genaue Antwort.
-
Bug Bingo!

Ich tippe auf einen Bufferoverflow. pos liegt zufällig zwischen dem Buffer und dem, was ohne die Variable während des Overflows überschrieben wurde.
-
#include <cstdlib> #include <iostream> #include <fstream> #include <vector> #include <string> #define NAME 0 #define COMMAND 1 #define TIME 2 #define BUFFERTIME 3 using namespace std; bool spec_getline(ifstream&,string&,short); class Command { public: string name; string command; string time; string buffertime; Command(string cstr_name = "",string cstr_command = "",string cstr_time = "",string cstr_buffertime = "") { name = cstr_name; command = cstr_command; time = cstr_time; buffertime = cstr_buffertime; } }; vector<string> names; void loadCommands(ifstream&,vector<Command*>&); int main(int argc, char *argv[]) { string temp(""); vector<Command*> commands; ifstream input("kfm720.cmd",ifstream::in); loadCommands(input,commands); for(int i = 0;i < commands.size();i++) cout << commands[i]->name << endl; system("PAUSE"); return EXIT_SUCCESS; } void loadCommands(ifstream& input,vector<Command*>& commands) { string temp(""); while(!input.eof()) { if((char)input.peek() == ';') { while((char)input.get() != '\n'); continue; } else { getline(input,temp,'\n'); if(temp.find("[Command]") != string::npos) { Command* temp_command = new Command; spec_getline(input,temp,NAME); temp_command -> name = temp; spec_getline(input,temp,COMMAND); temp_command -> command = temp;//.substr(temp.find('=')+1); spec_getline(input,temp,TIME); temp_command -> time = temp;//.substr(temp.find('=')+1); spec_getline(input,temp,BUFFERTIME); temp_command -> time = temp;//.substr(temp.find('=')+1); commands.push_back(temp_command); } } } } bool spec_getline(ifstream& input,string& temp,short type)//type = either if this searches for name, command,time or buffertime { streampos pos = input.tellg(); getline(input,temp,'\n'); switch(type) { case NAME: while((temp.find("[Command]") == string::npos) && !input.eof() && !input.fail()) { if(temp.find("name") != string::npos) { try { temp.erase(0,temp.find('=')+1); } catch(int a) { cout << "Missing equal sign" << endl; return false; } if(temp.find(';') != string::npos) temp.erase(temp.find(';')); while(temp.find(' ') != string::npos) temp.erase(temp.find(' '),1); while(temp.find('"') != string::npos) temp.erase(temp.find('"'),1); return true; } else if(!(input.eof() || input.fail())) { getline(input,temp,'\n'); } } return false; case COMMAND: while(temp.find("[Command]") == string::npos && !input.eof() && !input.fail()) { if(temp.find("command") != string::npos) { try { temp.erase(0,temp.find('=')+1); } catch(int a) { cout << "Missing equal sign" << endl; return false; } if(temp.find(';') != string::npos) temp.erase(temp.find(';')); while(temp.find(' ') != string::npos) temp.erase(temp.find(' '),1); return true; } else if(!(input.eof() || input.fail())) getline(input,temp,'\n'); } return false; case TIME: while(temp.find("[Command]") == string::npos && !input.eof() && !input.fail()) { if(temp.find("time") != string::npos) { try { temp.erase(0,temp.find('=')+1); } catch(int a) { cout << "Missing equal sign" << endl; return false; } if(temp.find(';') != string::npos) temp.erase(temp.find(';')); while(temp.find(' ') != string::npos) temp.erase(temp.find(' '),1); return true; } else if(!(input.eof() || input.fail())) getline(input,temp,'\n'); } return false; case BUFFERTIME: while(temp.find("[Command]") == string::npos && !input.eof() && !input.fail()) { if(temp.find("buffertime") != string::npos) { try { temp.erase(0,temp.find('=')+1); } catch(int a) { cout << "Missing equal sign" << endl; return false; } if(temp.find(';') != string::npos) temp.erase(temp.find(';')); while(temp.find(' ') != string::npos) temp.erase(temp.find(' '),1); return true; } else if(!(input.eof() || input.fail())) getline(input,temp,'\n'); } return false; default: cout << "No Type specified" << endl; return false; } }Ok, hier ist er.
Pos wird sonst überhaupt nicht verwendet. Wie sollte es zu einem codeseitigen Bug kommen?
-
kingcools2 schrieb:
Ok, hier ist er.
Pos wird sonst überhaupt nicht verwendet. Wie sollte es zu einem codeseitigen Bug kommen?Es könnte daran liegen, dass dein Code ehrlich gesagt ziemlich schlecht ist - du scheinst nicht verstanden zu haben wie das mit den Fehlerflags der Streams funktioniert. Bei 200 Zeilen bekommst du aber keine Einzelkritik zu den Fehlern und potentiellen Schwächen. Vielleicht wenn du beschreibst was dein Programm genau machen soll, kann ich dir mal eine gute Version zeigen.
Zu dem konkreten Fehler: Kannst du noch eine Beispieleingabedatei zeigen, dann sagen welches verhalten du mit und ohne die fragliche Zeile bekommst und was du eigentlich erwartest? Ich habe schon eine Ahnung, woran es liegt, aber da könnte so viel zusammenspielen, dass es einfacher ist das ganze mal eben durch den Debugger zu jagen (wieso machst du das eigentlich nicht?).
Dafür brauche ich jedoch Zeit die ich gerade nicht habe. Du musst also hoffen, dass ein anderer Forenteilnehmer Interesse zeigt oder etwas länger warten.
-
Danke für deine Antwort.
Ja bei den Fehlerflags bin ich mir tatsächlich unsicher, hab daher einfach sowohl endoffile als auch das failbit reingesetzt.http://rapidshare.com/files/429405264/kfm720.cmd
Das ist die Datei, bzw. der Dateientyp, welchen ich einlesen möchte.
Es gibt in diesem Typ Kommandoblöcke die von [Command] eingeleitet werden und danach max. nch 4 Zeilen enthalten.
Diese (4 Zeilen) möchte ich einlesen.
Ohne die speicherung der leseposition überspringt mein code derzeit aufeinanderfolgende [Command] Blöcke.Ausgeben sollte der Code derzeit nur den Namen der im jeweiligen [Command] block gegeben wird. Das tut er auch(bis auf das überspringen einzelner blöcke) auch, es sei denn ich packe den "pos = input.tellg()" dazu.
Dann ist die Ausgabe komplett fehlerhaft.
-
*push* ist mir immernoch völlig unerklärlich
-
Wie ich schon sagt, würde ich das ganze ganz anders machen. Das beantwortet zwar deine Frage nicht, aber das ist mir gerade zu wirr mich da durchzudenken. Irgendeine falsche Fehlerabfrage vermute ich, die einmal durch das tellg getriggert wird und einmal nicht. Wenn ich so eine Datei parsen müsste, dann würde ich das ungefähr so machen*:
#include<iostream> #include<string> #include<vector> #include<map> #include<stdexcept> #include<fstream> using namespace std; struct bad_line: public logic_error { bad_line(const string& line): logic_error("Syntax error in line :" + line){} }; class Command { private: string name; string command; string time; string buffertime; public: Command(map<string, string> fields): name(fields["name"]), command(fields["command"]), time(fields["time"]), buffertime(fields["buffertime"]) {} friend ostream& operator<< (ostream &out, const Command& command) { out << "name = " << command.name << '\n' << "command = "<< command.command << '\n' << "time = " << command.time << '\n' << "buffertime = " << command.buffertime << '\n'; return out; } }; template<char bra='[', char ket=']', char separator='='> class ParameterSet { private: multimap<string, map<string, string> > subsets; public: typedef vector<map<string, string> > subsettype; subsettype get_subset(const string &key) const { multimap<string, map<string, string> >::const_iterator lower = subsets.lower_bound(key);; multimap<string, map<string, string> >::const_iterator upper = subsets.upper_bound(key);; subsettype ret; for(multimap<string, map<string, string> >::const_iterator it=lower; it != upper; ++it) ret.push_back((*it).second); return ret; } ParameterSet(istream &in) throw (bad_line) { const char whitespace[] = "\n\r\t "; string line; string current_set_name; map<string, string> current_set; while (getline(in, line)) { // Trim comments size_t semicolon_pos = line.find_first_of(';'); if (semicolon_pos != string::npos) line.resize(semicolon_pos); if (line.size()) { // Does the line start with a opening bracket? size_t openingbracketpos = line.find_first_not_of(whitespace); if (openingbracketpos < line.size()-1 && line[openingbracketpos] == bra) // -1: There must be rrom for a closing bracket { // And does it have a closing bracket? size_t closingbracketpos = line.find_first_of(ket, openingbracketpos+1); if (closingbracketpos==string::npos) throw bad_line(line); // Found new subset, push old set and make a new one subsets.insert(pair<string, map<string,string> > (current_set_name, current_set)); current_set_name=line.substr(openingbracketpos+1,closingbracketpos-1); current_set.clear(); // cerr << "Found new subset. Name: \"" << current_set_name << '\"'<< endl; } else // Otherwise it is a new element of the subset { size_t keystartpos = line.find_first_not_of(whitespace); if (keystartpos != string::npos) // Line is not empty, let's look if the syntax is correct { size_t keyendpos = line.find_first_of(whitespace, keystartpos) -1; if (keystartpos == string::npos) throw bad_line(line); // We have a key string keyname = line.substr(keystartpos, keyendpos+1); // Is the next character a separator? size_t separatorpos = line.find_first_not_of(whitespace, keyendpos+1); if (separatorpos < line.size()-1 && line[separatorpos]==separator) { // Is the character after the separator a whitespace? size_t valuestartpos = line.find_first_not_of(whitespace, separatorpos+1); if (valuestartpos == string::npos) throw bad_line(line); // Everything is fine, find end of value size_t valueendpos = line.find_last_not_of(whitespace); string value = line.substr(valuestartpos, valueendpos); // Push new key value pair // cerr << " Found key \""<< keyname << "\" with value \""<<value<<'\"'<<endl; current_set.insert(pair<string, string>(keyname,value)); } else throw bad_line(line); } } } } // Delete empty sets: subsets.erase(""); } }; int main() { ifstream in ("kfm720.cmd"); ParameterSet<> params(in); ParameterSet<>::subsettype commandset = params.get_subset("Command"); vector<Command> commands; for(ParameterSet<>::subsettype::iterator it = commandset.begin(); it != commandset.end(); ++it) commands.push_back(Command(*it)); for(unsigned i=0; i<commands.size(); ++i) { cout << i+1 << ". Command:"<<'\n'<<commands[i]<<endl; } }Wie siehst kommt mein Ansatz völlig ohne tellg aus und ist auch viel allgemeiner. Als Nebenprodukt zu dem Ansatz habe ich nämlich auch gleich die gesamte Datei eingelesen und alle Kategorien verarbeitet. Du könntest nun ganz einfach die alles weiterverarbeiten mit den Methoden die ich am Beispiel "Command" vorführe.
Und es ist sogar viel kürzer als dein Programm!
edit: Ich hoffe es ist verständlich, ich habe extra nicht gegeizt mit Kommentaren, zumindest beim eigentlichen Parsevorgang. Ich habe aber nicht die höheren Sprachelemente selbst kommentiert sondern einfach benutzt in der Annahme, dass du diese kennst. Falls trotzdem Unklarheiten bestehen, nur heraus damit!
*: Oder ein fertiges Parserpaket benutzen, das wäre natürlich viel sinnvoller! Aber einmal selber machen macht auch Spaß.
-
vielen dank dafür
Sehr nett.
Mir ist auch eine variante ohne tellg() eingefallen.
Ich schau mir deine fassung nachher an muss jetzt weg
(Ich denke immernoch dass es ein bug ist:P)
-
kingcools2 schrieb:
vielen dank dafür
Sehr nett.
Mir ist auch eine variante ohne tellg() eingefallen.
Ich schau mir deine fassung nachher an muss jetzt weg
(Ich denke immernoch dass es ein bug ist:P)Nee, das wird so etwas sein wie, dass tellg bei Dateiende auch Fehlerflags triggert (das tut es soweit ich weiß) und du diesen Fall nicht betrachtest. Aber da ich es mir nicht so genau angeguckt habe, kann ich es nicht mit Sicherheit sagen. Neuschreiben war da einfacher.
P.S.: Sehe ich jetzt erst: Das Kommentarzeichen gehört bei mir natürlich auch templatisiert, damit alles einheitlich ist. Das überlasse ich dir mal zur Übung. Das kommt davon, wenn man sich bei der Hälfte des Programms entschließt oben nochmal gravierende Änderungen vorzunehmen.
-
Sage deinem Stream mal direkt nach dem Definieren:
input.exceptions(ifstream::eofbit | ifstream::failbit | ifstream::badbit);Vielleicht fliegt die dann ne Exception. Aber ich halts wie SeppJ: Soviel komischen Code lese ich mir nicht durch.
-
Danke an euch, ich probier mal meinen Code aufzubessern, die Variante von Sepp ist echt verdammt elegant.
Danke sehr dafür