Kompiliertes Programm verhält sich unter Linux Mint anders als unter Windows 7 ?



  • Hallo zusammen,

    folgender Code soll meine Problematik verdeutlichen - der Sinn oder Unsinn von diesem Programm ist an dieser Stelle bitte zu vernachlässigen 😉 Es wird einfach nach einer beliebigen Gleitkommazahl gefragt und die Anzahl der Ziffern vor dem Punkt werden anschließend gezählt und ausgegeben.
    Unter Windows 7 & mit Visual Studio funktioniert das alles hervorragend:

    int main()
    {
    	cout << endl;
    
    	string zahl;
    	int counter = 0;
    
    	cout << " Gleitkommazahl eingeben (zB 1234.56): ";
    	cin >> zahl;
    
    	for (char& zeichen : zahl)
    	{
    		if (zeichen == '.')
    			break;
    		else
    			counter++;
    	}
    
    	cout << "\n Vor dem Punkt stehen " << counter << " Ziffern.\n";
    
    	getchar();
    	return 0;
    }
    

    Auf meinem Laptop habe ich Linux Mint Cinnamon (18.1 Serena) installiert, dazu die IDE von Code::Blocks sowie den g++ Compiler über die übliche Paketverwaltung heruntergeladen. Jetzt funktioniert das obige Programm überraschenderweise nicht: Wenn es kompiliert wird bzw. nachdem man nach der Abfrage "Gleitkommazahl eingeben (zB 1234.56):" einen Wert eingegeben hat, kann man auf der Konsole so oft ENTER drücken oder eben irgend ein Zeichen eingeben, bis man keinen Bock mehr hat (...) - kurz: Es passiert nichts mehr und das Programm bestimmt nicht die Anzahl der Ziffern vor dem Punkt - es reagiert nicht mehr und man ist gezwungen, die Konsole zu schließen! Der Compiler meldet allerdings keine Fehlermeldung.
    Warum ist das so? Auf Windows (mit Visual Studio) klappt alles reibungslos. 😕
    Andere normale Testprogramme (z.B. Hello World oder die Berechnung von Potenzen) funktionieren jedoch wie unter VS auch mit Code::Blocks inkl. g++ Compiler.

    Ich freue mich wirklich über jede Unterstützung!



  • Nach eingehender systemanalytischer Auswertung (Advanced Business
    Security Consideration) des Sachverhaltes wird der Generic Risk
    Exposure Level in einer Secondary Transitional Incidence Kategorie
    eingestuft. Das Aggregated Detriment verbleibt also im Admissible
    Range. Ein Grund, auf per se löchrige Fricklerware umzusteigen, wäre
    eine drastische Gefährdung der Business Integrity, und würde, wie
    Studien gezeigt haben, bzgl. der Long-Term Profitability zu einer
    dramatischen Verschlechterung führen. Betrachtet man den Zusammenhang
    zwischen Marktanteil und Meldung über Fehler, muss schlussendlich
    folgende Reasonable Business Conclusion getroffen werden: der gcc
    taugt nichts, es wird weiterhin uneingeschränkt empfohlen, die
    Microsoft® Visual Studio Premium-IDE zu verwenden.



  • Kenner des gcc schrieb:

    Nach eingehender systemanalytischer Auswertung (Advanced Business
    Security Consideration) des Sachverhaltes wird der Generic Risk
    Exposure Level in einer Secondary Transitional Incidence Kategorie
    eingestuft. Das Aggregated Detriment verbleibt also im Admissible
    Range. Ein Grund, auf per se löchrige Fricklerware umzusteigen, wäre
    eine drastische Gefährdung der Business Integrity, und würde, wie
    Studien gezeigt haben, bzgl. der Long-Term Profitability zu einer
    dramatischen Verschlechterung führen. Betrachtet man den Zusammenhang
    zwischen Marktanteil und Meldung über Fehler, muss schlussendlich
    folgende Reasonable Business Conclusion getroffen werden: der gcc
    taugt nichts, es wird weiterhin uneingeschränkt empfohlen, die
    Microsoft® Visual Studio Premium-IDE zu verwenden.

    Hundert Punkte beim Bullshit-Bingo! 😃
    Hätte nur noch Etwas mit Cloud oder BigData gefehlt. 😉



  • Die Distributed Program Analyis zeigt, dass Big Data besser als die Cloud
    performed.



  • Ich habe das Problem beheben können - ich musste in den Einstellungen (IDE von Code::Blocks) unter Compiler nur einen Haken neben C++14 setzen, seitdem klappt es endlich.

    Aber irgendwie scheint sich der Compiler unter Linux Mint insgesamt ein wenig anders zu verhalten, als von Microsoft VS 15 gewohnt... Wenn ich zum Beispiel eine .txt Datei mit beliebigen Zahlen einlesen möchte, funktioniert das nicht, sobald sich in dieser Text-Datei auch nur ein unsichtbarer Zeilenumbruch am Ende befinden sollte - wird dieser entfernt und die Datei erneut gespeichert, funktioniert wieder alles. Unter Windows ist das anscheinend kein Problem, da können noch so viele Zeilenumbrüche vorhanden sein, da passiert nix. Ich hoffe, ihr versteht was ich meine.
    Gibt es für dieses Phänomen eine Erklärung? Das würde mich interessieren. (Bin Anfänger, was Linux betrifft ...)


  • Mod

    Ich vermute eher, dass deine Programme fehlerhaft sind. Beispielsweise klingt dein Einleseproblem sehr nach while(!eof)-Quatsch. Aber ohne Code und mit solch genauen Fehlerbeschreibungen wie "funktioniert nicht" kann man das nicht genauer analysieren.



  • Bei mir hat es mit g++ -std=c++11 test.cpp geklappt.



  • unwichtig schrieb:

    Bei mir hat es mit g++ -std=c++11 test.cpp geklappt.

    Danke für deine Rückmeldung! Ich hab's mittlerweile auch hinbekommen, hatte erst vergessen, in der Code::Blocks IDE unter Global compiler settings -> Compiler Flags -> General das Häkchen zu setzen - da war erst nichts markiert.

    SeppJ schrieb:

    Aber ohne Code und mit solch genauen Fehlerbeschreibungen wie "funktioniert nicht" kann man das nicht genauer analysieren.

    Sorry, ich formulier's gerne genauer. Ich werde versuchen, die Problematik möglichst genau zu erklären.
    Mein Programm soll Werte aus einer normalen Textdatei einlesen - diese stehen dort jeweils alle untereinander "Zeile für Zeile", das könnten z.B. Temperaturmesswerte sein. Das Programm liest die Werte ein und speichert sie in einen string Vector ab, wandelt sie anschließend in double-Werte um und speichert sie in einem neuen Vector vom Typ double ab. Der Anwender soll darüber hinaus die Möglichkeit haben, die Anzahl der Nachkommastellen festzulegen. Es werden der Mittelwert, die mittlere quadrat. Stand. Abweichung sowie die "normale" Standardabweichung berechnet und anschließend auf der Konsole ausgegeben. Der Quellcode:

    #include <iostream>
    #include <sstream>
    #include <string>
    #include <fstream>
    #include <vector>
    #include <math.h>
    #include <iomanip>
    
    using namespace std;
    
    int main()
    {
    	cout << fixed;
    
    	vector<string> str_vec;   // Vector zum Einlesen der Werte aus einer .txt Datei
    	vector<double> doub_vec;  // Vector zum Umwandeln der string-Werte in double
    
            //
            // Lese Werte ein
            //
    	string quelldateiname;
    	cout << " Quelldatei? ";
    	cin >> quelldateiname;
    	ifstream quelle (quelldateiname);
    	if (!quelle)
    	{
    		cerr << quelldateiname << " kann nicht geöffnet werden!\n";
    	}
    
    	else
    	{
    		while (quelle)
    		{
    			string zeile;
                getline(quelle, zeile);
                str_vec.push_back(zeile);
    		}
    	}
    
    	str_vec.pop_back();
    	cout << endl;
    
            //
            // wandele Werte vom Typ string in double um und speichere sie im neuen Vektor ab
            //
    	for (int n = 0; n < str_vec.size(); n++)
    	{
    		string s = str_vec[n];
    		double d = stod(s);
    		doub_vec.push_back(d);
    	}
    
    	//
    	// Lege die Anzahl der Nachkommastellen fest
    	//
    	int rundung = 0;
    	do
    	{
    		cout << " Anzahl der Nachkommastellen (max. 6)? ";
    		cin >> rundung;
    		if (rundung < 0 || rundung > 6)
    		{
    			cout << " Unzulaessige Eingabe.";
    		}
    	}
    	while (rundung < 0 || rundung > 6);
    	cout << setprecision(rundung);
    
    	//
    	// Berechne den Mittelwert
    	//
    	double sum = 0;
    	double x_mittel = 0;
    	for (int i = 0; i < doub_vec.size(); i++)
    	{
    		sum  += doub_vec[i];
    	}
    
    	x_mittel = sum / doub_vec.size();
    
    	cout << "\n Der Mittelwert betraegt x_mittel = " << x_mittel << endl;
    
    	//
    	// Berechne die mittlere quadrat. Std.Abw.
    	//
    	double zaehler = 0;
    	double quStdAb = 0;
    	for (int i = 0; i < doub_vec.size(); i++)
    	{
    		zaehler += pow((doub_vec[i] - x_mittel), 2);
    	}
    
    	quStdAb = zaehler / (doub_vec.size() - 1);
    
    	cout << "\n Die mittlere quadrat. Standard-Abw betraegt s^2 = " << quStdAb << endl;
    
    	//
    	// Berechne Standard-Abweichung
    	//
    	cout << "\n Die Standardabweichung betraegt s = " << sqrt(quStdAb) << endl;
    
    	cout << endl;
    	getchar();
    	return 0;
    }
    

    Wenn sich nun in einer Textdatei - ganz am Ende, also nach dem letzten Messwert - unsichtbare Zeilenumbrüche befinden, dann meldet die Konsole (nur unter Linux Mint; IDE Code::Blocks) nach Eingabe "Quelldatei ?" folgende Fehlermeldung aus:

    terminate called after throwing an instance of 'std::invalid_argument'
    what(): stod
    Aborted

    Process returned 134 (0x86) execution time : 22.994 s
    Press ENTER to continue.

    Werden die Zeilenumbrüche in dieser Datei manuell entfernt, dann klappt alles einwandfrei. Unter Windows 7 (IDE Visual Studio) gibt es diese Fehlermeldung allerdings nicht und es läuft mit oder ohne Zeilenumbrüche; daher ursprünglich der Gedanke, ob die Compiler unter den beiden Betriebssystemen ein wenig gegensätzlich reagieren? Vielleicht ist aber auch mein Quellcode tatsächlich fehlerhaft oder unsauber - ich freue mich natürlich sehr über Ratschläge, Hinweise und etc. ! 🙂


  • Mod

    Sagte ich doch, dass das ein while(!eof) ist. Es ist hier aber noch mit weiteren Problemen kombiniert.

    Also:

    • Eine Leseschleife sieht in allen C-artigen Sprachen immer so aus:
    while(leseoperation_erfolgreich)
    {
      verarbeite_daten;
    }
    

    Niemals

    while(stream_gültig)
    {
      lese_daten;
      verarbeite_daten;
    }
    

    Denn wie sonst willst du mitbekommen, ob eine Leseaktion erfolgreich war oder nicht? Wenn nicht, dann verarbeitest du Datenmüll.

    Wer dir das so beigebracht hat, hat keine Ahnung. Lerne nichts weiter aus dieser Quelle!

    • Wenn du erst einen String aus einem Stream liest und diesen dann wieder einem Parser vorsetzt, wieso hast du dann nicht gleich den Inhalt des Streams an den Parser übergeben? Die Streams können doch bereits super selber Zahlen interpretieren. Wieso der Umweg?
    • Wieso das abstürzt sollte mit der Fehlermeldung doch klar sein, besonders wenn du mal die Dokumentation von stod liest: Du hast Datenmüll als Argument übergeben, nämlich wahrscheinlich leere Zeilen. Du solltest erstens niemals Datenmüll verarbeiten und zweitens natürlich trotzdem eine Behandlung für die möglichen Fehlerfälle haben.

    Du könntest deine gesamten Zeilen 32-51 wohl durch

    double value;
    while(quelldatei >> value)
      doub_vec.push_back(value)
    

    ersetzen und es wäre viel kürzer und würde viel zuverlässiger funktionieren. Es macht nicht exakt das gleiche wie dein momentaner Code (bei dem nur eine Zahl in einer Zeile stehen darf, hier ist es egal), aber es ist wahrscheinlich das was du möchtest.
    Oder noch ein bisschen kürzer (und schwerer lesbar), indem du die Zeile 16 nach 32 holst (Variablen sollte man ohnehin immer erst dann definieren, wenn man sie das erste mal braucht):

    vector<double> double_vec(istream_iterator<double>(quelldatei), istream_iterator<double>());
    

    Weiter habe nicht nicht gelesen! Kann sein, dass da noch mehr Verbesserungsmöglichkeiten kommen. Rein konzeptionell könntest du dir aber das ganze Zwischenspeichern der Werte sowieso sparen, wenn du nur einen Mittelwert und eine Standardabweichung berechnen möchtest. Das kannst du alles on the fly direkt beim Einlesen machen. Zum Beispiel Mittelwert:

    double value;
    double sum = 0;
    unsigned counter = 0;
    while(quelldatei >> value)
    {
      sum += value;
      ++counter;
    }
    double mittelwert = sum / counter;
    

    Standardabweichung ist ein bisschen trickreicher, das überlasse ich dem geneigten Leser zur Übung (oder zum googeln 😉 ).



  • Super, ein herzliches Dankeschön für deinen ausführlichen Beitrag, SeppJ! 🙂 Ich schätze das wirklich sehr!

    Somit habe ich wieder etwas dazugelernt, jetzt klappt's auch einwandfrei und genau so, wie ich mir das vorgestellt habe. Klingt alles einleuchtend - es kann so einfach gehen und ich denke mal wieder wie immer etwas zu kompliziert nach ...
    Ich habe mich bezogen auf die Leseschleife teilweise von dem Buch "Der C++-Programmierer" von U. Breymann inspirieren lassen, allerdings das Ganze auch selber etwas ungeschickt umgebaut. Das Beispiel aus seinem Buch war eher für die Ausgabe von Werten auf der Konsole gedacht, also in seinem Beispiel wurde in der while-Schleife nichts verarbeitet.

    Die Standardabweichung werde ich mal probieren, ist auf jeden Fall eine gute Übungsaufgabe!



  • axels. schrieb:

    Hundert Punkte beim Bullshit-Bingo! 😃
    Hätte nur noch Etwas mit Cloud oder BigData gefehlt. 😉

    Das war 2006 (noch) nicht so der Hype.


Anmelden zum Antworten