Kompilierung Taschenrechner Punkt vor Strich + Konstruktor
-
Hallo,
ich arbeite mit dem Buch "Einführung in die Programmierung mit C++"
von Bjarne Stroustrup. Es geht um ein Beispielprogramm "Taschenrechner mit
Punkt vor Strich".Ich habe den Code, in dem der eigene Parser und das Erstellen eigener Datentypen (Tokens)
behandelt wird größtenteils verstanden, jedoch
1. bekomme ich es nicht hin ihn zu kompilieren
2. habe ich den Konstruktor (class Token {...}
) in einem Testprogramm ausprobiert, was nicht funktioniert hat; soll ich den Konstruktor wie hier https://de.wikibooks.org/wiki/C%2B%2B-Programmierung/_Eigene_Datentypen_definieren/_Erstellen_und_Zerst%C3%B6ren machen?
// // Dieser Beispielcode stammt aus Kapitel 6.9 "Programmstruktur" des Buches // "Einführung in die Programmierung mit C++" von Bjarne Stroustrup // #include "std_lib_facilities.h" //------------------------------------------------------------------------------ class Token { public: char kind; // welche Kategorie von Token double value; // für Zahlen: ein Wert Token(char ch) // erstelle ein Token aus einem char :kind(ch), value(0) { } Token(char ch, double val) // erstelle ein Token aus einem char und einem double :kind(ch), value(val) { } }; //------------------------------------------------------------------------------ class Token_stream { public: Token_stream(); // erstelle einen Token_stream, der aus cin liest Token get(); // lies ein Token ein (get() ist anderswo definiert) void putback(Token t); // lege ein Token zurück private: bool full; // befindet sich ein Token im Puffer? Token buffer; // hier legen wir ein Token ab, das mit putback() // zurückgestellt wurde }; //------------------------------------------------------------------------------ // Der Konstruktor setzt full auf false, um anzuzeigen, dass der Puffer leer ist: Token_stream::Token_stream() :full(false), buffer(0) // kein Token im Puffer { } //------------------------------------------------------------------------------ // Die Memberfunktion putback() stellt ihr Argument zurück in den Puffer von Token_stream: void Token_stream::putback(Token t) { if (full) error("putback(): Zurueckstellen nicht moeglich, Puffer voll"); buffer = t; // kopiere t in den Puffer full = true; // Puffer ist jetzt voll } //------------------------------------------------------------------------------ Token Token_stream::get() { if (full) { // gibt es bereits ein fertiges Token? // Token aus dem Puffer entfernen full=false; return buffer; } char ch; cin >> ch; // beachten Sie, dass >> Whitespace-Zeichen wie // Leerzeichen, Zeilenumbruch, Tabulatorzeichen, etc. überspringt switch (ch) { case ';': // für "Ausgeben" case 'q': // für "Verlassen" case '(': case ')': case '+': case '-': case '*': case '/': return Token(ch); // jedes Zeichen repräsentiert sich selbst case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { cin.putback(ch); // lege die Ziffer zurück in den Eingabestream double val; cin >> val; // lies eine Gleitkommazahl return Token('8',val); // '8' repräsentiert "eine Zahl" } default: error("Ungueltiges Token"); } } //------------------------------------------------------------------------------ Token_stream ts; // stellt get() und putback() zur Verfügung //------------------------------------------------------------------------------ double expression(); // Deklaration, damit primary() expression() aufrufen kann //------------------------------------------------------------------------------ // behandelt Zahlen und Klammern double primary() { Token t = ts.get(); switch (t.kind) { case '(': // behandle'(' Ausdruck ')' { double d = expression(); t = ts.get(); if (t.kind != ')') error("')' erwartet"); return d; } case '8': // wir verwenden '8' zur Repräsentation einer Zahl return t.value; // liefere den Wert der Zahl zurück default: error("Faktor erwartet"); } } //------------------------------------------------------------------------------ // behandelt *, / und % double term() { double left = primary(); Token t = ts.get(); // lies das nächste Token aus dem Token-Stream ein while(true) { switch (t.kind) { case '*': left *= primary(); t = ts.get(); break; case '/': { double d = primary(); if (d == 0) error("Division durch null"); left /= d; t = ts.get(); break; } default: ts.putback(t); // stelle t wieder zurück in den Token-Stream return left; } } } //------------------------------------------------------------------------------ // behandelt + und – double expression() { double left = term(); // liest einen Token ein und wertet ihn aus Token t = ts.get(); // lies das nächste Token aus dem Token-Stream ein while(true) { switch(t.kind) { case '+': left += term(); // werte Term aus und addiere t = ts.get(); break; case '-': left -= term(); // werte Term aus und subtrahiere t = ts.get(); break; default: ts.putback(t); // stelle t wieder zurück in den Token-Stream return left; // keine weiteren + oder –; Antwort zurückliefern } } } //------------------------------------------------------------------------------ int main() try { double val = 0; while (cin) { Token t = ts.get(); if (t.kind == 'q') break; // 'q' für "verlassen" if (t.kind == ';') // ';' für "jetzt ausgeben" cout << "=" << val << '\n'; else ts.putback(t); val = expression(); } } catch (exception& e) { cerr << "Fehler: " << e.what() << '\n'; return 1; } catch (...) { cerr << "Hoppla: unbekannte Ausnahme!\n"; return 2; } //------------------------------------------------------------------------------
Fehlermeldungen (Visual Studio):
Fehler LNK1120 1 nicht aufgelöste Externe ConsoleApplication2 C:\Users\test\documents\visual studio 2015\Projects\ConsoleApplication2\Debug\ConsoleApplication2.exe 1
Fehler LNK2019 Verweis auf nicht aufgelöstes externes Symbol "_main" in Funktion ""int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)". ConsoleApplication2 C:\Users\test\documents\visual studio 2015\Projects\ConsoleApplication2\ConsoleApplication2\MSVCRTD.lib(exe_main.obj) 1
Ich habe es auch ohne die std_lib_facilities (mag ich nicht) und nur mit der <iostream> probiert, aber ohne Erfolg.
Vielen Dank im Voraus!
mfg
mrcharter
-
Vermutlich hast du kein Konsolenprojekt angelegt. Dann erwartet Visual Studio WinMain statt main.
-
Vielen Dank für die Antwort,
aber daran liegt es nicht, es ist ein Konsolenprojekt (Visual Studio 2015). Es liegt auch nicht an Visual Studio, habe es auch in Codeblocks unter Linux ausprobiert.MfG
mrcharter
-
Du musst den Rumpf deiner main-Funktion in geschweifte Klammern setzen.
-
Danke,
jedoch kommen immernoch die beiden LINK Fehler.
MfG
mrcharter
-
Welchen Code übersetzt du?
-
Naja den Code oben, die Klammern der main-Funktion habe ich natürlich berichtigt.
MfG
mrcharter
-
Der funktioniert wunderbar, sogar ohne die zusätzlichen Klammern.
-
Woher hast du den Header? Der funktioniert:
http://stroustrup.com/Programming/PPP2code/std_lib_facilities.h
-
MFK schrieb:
Du musst den Rumpf deiner main-Funktion in geschweifte Klammern setzen.
weiß nicht genau, was der standard hierzu sagt, aber msvc (2015) zumindest compiliert
int main() try{} catch(...){}
anstandslos
hatte ich auch als erstes probiert als ich den thread gefunden habe und war verwundert
-
manni66 schrieb:
Woher hast du den Header? Der funktioniert:
http://stroustrup.com/Programming/PPP2code/std_lib_facilities.h
Ich benutze den Header. Kann das an Visual Studio liegen (Ich habe auch das Problem, dass Visual Studio abstürzt, wenn ich ein neues Projekt erstelle)?
Und was genau ist jetzt der Unterschied zwischen dem Konstruktor von dem Taschenrechnerprogramm
Token {...}
und soeinem Konstruktor https://de.wikibooks.org/wiki/C%2B%2B-Programmierung/_Eigene_Datentypen_definieren/_Erstellen_und_Zerstören ?
MfG
mrcharter
-
mrcharter schrieb:
Kann das an Visual Studio liegen (Ich habe auch das Problem, dass Visual Studio abstürzt, wenn ich ein neues Projekt erstelle)?
Installier bitte VS richtig, bzw. beheb die offfensichtlichen Probleme mit Deiner Installation.
unskilled schrieb:
weiß nicht genau, was der standard hierzu sagt, aber msvc (2015) zumindest compiliert
int main() try{} catch(...){}
anstandslos
Siehe hier: http://en.cppreference.com/w/cpp/language/function-try-block
-
mrcharter schrieb:
Und was genau ist jetzt der Unterschied zwischen dem Konstruktor von [code="cpp"]Token {...}[code="cli"] und soeinem Konstruktor https://de.wikibooks.org/wiki/C%2B%2B-Programmierung/_Eigene_Datentypen_definieren/_Erstellen_und_Zerstören machen?
Keine Ahnung. Deine Frage ist völlig kaputt. Es gibt einen Vorschauknopf, da kann man sich alles ansehen, bevor man es abschickt.
-
manni66 schrieb:
Keine Ahnung. Deine Frage ist völlig kaputt. Es gibt einen Vorschauknopf, da kann man sich alles ansehen, bevor man es abschickt.
Sorry, war ein Versehen, habe es berichtigt.
Und was genau ist jetzt der Unterschied zwischen dem Konstruktor von dem Taschenrechnerprogramm
C++:
Token {...}
und soeinem Konstruktor https://de.wikibooks.org/ ....... tellen_und_Zerst%C3%B6ren ?Hat darauf jemand eine Antwort?
Ich bin jetzt dabei Visual Studio zu reparieren, und habe den Code unter Codeblocks ausprobiert.
Ich habe folgende Fehlermeldungen bekommen:||=== Build: Debug in trtest (compiler: GNU GCC Compiler) ===| /usr/include/c++/4.9/backward/backward_warning.h|32|warning: #warning This file includes at least one deprecated or antiquated header which may be removed without further notice at a future date. Please use a non-deprecated interface with equivalent functionality instead. For a listing of replacement headers and interfaces, consult the file backward_warning.h. To disable this warning use -Wno-deprecated. [-Wcpp]| /usr/include/c++/4.9/bits/locale_facets_nonio.h|1869|error: template-id ‘do_get<>’ for ‘String std::messages<char>::do_get(std::messages_base::catalog, int, int, const String&) const’ does not match any template declaration| /usr/include/c++/4.9/bits/locale_facets_nonio.h|1869|note: saw 1 ‘template<>’, need 2 for specializing a member function template| /home/tobias/Dokumente/C++/trtest/main.cpp||In member function ‘Token Token_stream::get()’:| /home/tobias/Dokumente/C++/trtest/main.cpp|84|warning: control reaches end of non-void function [-Wreturn-type]| /home/tobias/Dokumente/C++/trtest/main.cpp||In function ‘double primary()’:| /home/tobias/Dokumente/C++/trtest/main.cpp|113|warning: control reaches end of non-void function [-Wreturn-type]| ||=== Build failed: 1 error(s), 3 warning(s) (0 minute(s), 2 second(s)) ===|
Kann mir jemand sagen, was ich falsch mache?
Vielen Dank im Voraus!
MfG
mrcharter
-
/usr/include/c++/4.9/backward/backward_warning.h|32|warning: #warning This file includes at least one deprecated or antiquated header which may be removed without further notice at a future date. Please use a non-deprecated interface with equivalent functionality instead. For a listing of replacement headers and interfaces, consult the file backward_warning.h. To disable this warning use -Wno-deprecated. [-Wcpp]|
steht doch alles drin. welcher header das ist, weiß ich aber nicht. evtl strstream oder so was includiert?
/usr/include/c++/4.9/bits/locale_facets_nonio.h|1869|error: template-id ‘do_get<>’ for ‘String std::messages<char>::do_get(std::messages_base::catalog, int, int, const String&) const’ does not match any template declaration| /usr/include/c++/4.9/bits/locale_facets_nonio.h|1869|note: saw 1 ‘template<>’, need 2 for specializing a member function template|
vergleich doch mal aufruf und derklaration der fkt.
/home/tobias/Dokumente/C++/trtest/main.cpp||In member function ‘Token Token_stream::get()’:| /home/tobias/Dokumente/C++/trtest/main.cpp|84|warning: control reaches end of non-void function [-Wreturn-type]|
es kann passieren, dass deine fkt nichts zurückgibt, obwohl sie das muss.
das solltest du selbst erkennen./home/tobias/Dokumente/C++/trtest/main.cpp||In function ‘double primary()’:| /home/tobias/Dokumente/C++/trtest/main.cpp|113|warning: control reaches end of non-void function [-Wreturn-type]|
noch mal.
bb
PS: wenn du so weiter machst, kann es ganz schnell passieren, dass du gar keine antworten mehr bekommst, weil du etwas wenig eigeninitiative zeigst.
-
mrcharter schrieb:
Und was genau ist jetzt der Unterschied zwischen dem Konstruktor von dem Taschenrechnerprogramm
C++:
Token {...}
und soeinem Konstruktor https://de.wikibooks.org/ ....... tellen_und_Zerst%C3%B6ren ?Hat darauf jemand eine Antwort?
Ich sehe keinen Unterschied. Was meinst du?
mrcharter schrieb:
und habe den Code unter Codeblocks ausprobiert.
Ich habe folgende Fehlermeldungen bekommen:Mit einem gcc 4.9? Keine Ahnung ob es damit klappt. Mit gcc 6.3 auf Linux geht es mit dem gezeigten Code und der von mir verlinkten std_lib_facilities.h.
-
Vielen Dank für die Antworten.
Code:
/usr/include/c++/4.9/bits/locale_facets_nonio.h|1869|error: template-id ‘do_get<>’ for ‘String std::messages<char>::do_get(std::messages_base::catalog, int, int, const String&) const’ does not match any template declaration|
/usr/include/c++/4.9/bits/locale_facets_nonio.h|1869|note: saw 1 ‘template<>’, need 2 for specializing a member function template|vergleich doch mal aufruf und derklaration der fkt.
Habe jetzt alle bis auf die beiden berichtigt. Leider habe ich mich nicht mit Templates nicht beschäftigt und kann darum nichts damit anfangen (bzw. habe es mir angeschaut und bin leider zu keinem Ergebnis gekommen). Es wäre nett, wenn mir jemand sagen kann, was ich noch ändern muss damit es passt.
Ich sehe keinen Unterschied. Was meinst du?
Hat sich erledigt.
MfG
mrcharter
-
mrcharter schrieb:
was ich noch ändern muss damit es passt
Nichts. Installiere einen aktuellen Compiler (für Windows VS2017).