warning: ignoring return value



  • <klugscheiß>
    Dravere: 0 vergessen 😉
    </klugscheiß>


  • Administrator

    pumuckl schrieb:

    <klugscheiß>
    Dravere: 0 vergessen 😉
    </klugscheiß>

    AAAAAAAAAAAARRRRRRGGGGGGGHHHH ... aber danke, ist nun korrigiert 🙂
    Ich sitze hier noch in Pyjama und Morgenmantel vor dem PC, ist wohl noch die Müdigkeit vom Morgen mit dabei. Egal wie spät es gerade ist 😉

    Grüssli



  • tu ichs? oder lass ichs? ach ich tus einfach

    <klugscheiß>
    Dravere: nun akzeptiert die Funktion aber auch strings wie "00000000000000"
    </klugscheiß>

    *duck und wegrenn* 😃


  • Administrator

    Und was ist daran auszusetzen? Das ist eine Ganzzahl. Da sehe ich kein Problem damit ...

    Grüssli



  • Dravere schrieb:

    In C++ macht man Zahlenkonvertierungen anders.

    Da hast du natürlich Recht. Aber trotzdem ist es doch völlig legitim, den Rückgabewert von strtol() zu ignorieren, oder nicht? In C würde man ja vor dem selben Problem stehen.

    std::string foo;
    std::istringstream ss(foo);
    
    long l;
    if(ss >> l)
    {
      // Erfolgreich.
    }
    else
    {
      // Fehler.
    }
    

    Jo, das scheint mir nicht die schlechteste Lösung zu sein... Auch wenn es irgendwie schon schön wäre, wenn ich mir die eigentliche Umwandlung komplett sparen könnte.

    Dravere schrieb:

    Überprüfung ob es eine Ganzzahl ist:

    std::string foo;
    
    if(foo.find_first_not_of("0123456789") == std::string::npos)
    {
      // Der String besteht nur aus den Zeichen 0,1,2,3,4,5,6,7,8 und 9
      // Ist also eine Ganzzahl.
    }
    else
    {
      // Da wurde auch noch etwas anderes gefunden.
    }
    

    Das funktioniert so allerdings nicht wirklich für ganze Zahlen, die ja schließlich auch negativ sein können...


  • Administrator

    dooooomi schrieb:

    Aber trotzdem ist es doch völlig legitim, den Rückgabewert von strtol() zu ignorieren, oder nicht? In C würde man ja vor dem selben Problem stehen.

    Ich denke eigentlich schon auch. Hast du vielleicht irgendwie die Warnungsstufe zu hoch eingestellt? Aber wie gesagt, da muss du mal im Compilerforum nachfragen. Ich kenne mich mit dem gcc zu wenig aus.

    dooooomi schrieb:

    Das funktioniert so allerdings nicht wirklich für ganze Zahlen, die ja schließlich auch negativ sein können...

    Wie die Leute doch pingelig sind ...

    bool is_integer(std::string const& foo)
    {
      if(foo.size() > 0)
      {
        std::string::size_type start = 0;
    
        if(foo[0] == '-')
        { start = 1; }
    
        if(foo.find_first_not_of("0123456789", start) == std::string::npos)
        { return true; }
      }
    
      return false;
    }
    

    Ansonsten könntest du auch die Boost.Regex verwenden.

    Grüssli



  • Dravere schrieb:

    Konvertierung von String zu Zahl in C++:

    std::string foo;
    std::istringstream ss(foo);
    
    long l;
    if(ss >> l)
    {
      // Erfolgreich.
    }
    else
    {
      // Fehler.
    }
    

    Moment mal... das macht ja doch nicht das selbe!

    Der Sinn meines Codes (mit strtol) war ja herauszufinden, ob der String ein Integer enthält, und zwar nur ein Integer und mehr nicht. In der Stream-Variante kann nach der Zahl noch alles Mögliche folgen, und ich würde es nicht merken.

    Also, die Frage bliebe: Wie kann ich strtol() durch sauberes C++ ersetzen, das genau den selben Effekt hat, und nicht aus einer einzigen Zeile 10 Zeilen oder mehr macht?


  • Administrator

    dooooomi schrieb:

    Moment mal... das macht ja doch nicht das selbe!

    Ich habe ja gesagt, dass es eine Konvertierung ist.
    Allerdings könntest du das auch noch implementieren. Kurzes Programm zum selber testen:

    #include <string>
    #include <sstream>
    #include <iostream>
    
    bool is_integer(std::string const& text)
    {
    	long number;
    	std::stringstream ss(text);
    	return ss >> number && ss.eof();
    }
    
    int main() 
    {
    	std::string line;
    	std::getline(std::cin, text);
    
    	while(line.compare("exit") != 0)
    	{
    		if(is_integer(line))		
    		{ std::cout << "Number!" << std::endl; }
    		else
    		{ std::cout << "NaN!" << std::endl; }
    
    		std::getline(std::cin, line);
    	}
    
    	return 0;
    }
    

    dooooomi schrieb:

    Also, die Frage bliebe: Wie kann ich strtol() durch sauberes C++ ersetzen, das genau den selben Effekt hat, und nicht aus einer einzigen Zeile 10 Zeilen oder mehr macht?

    Wie glaubst du ist strtol intern aufgebaut? Wahrscheinlich mit mehr als 10 Zeilen. Solche Funktionen lagert man in eine Headerdatei aus und macht sie inline. Dann kann man sie immer wieder verwenden.

    strtol ist nämlich für deinen Fall völlig verkehrt. Du willst ja nicht die Zahl konvertieren, sondern nur feststellen, ob es eine Zahl ist. Genauso, wie die obige Lösung eigentlich verkehrt ist.
    Beim Programmieren sollte man nicht möglichst wenig Zeilen schreiben, dass ist der falsche Weg!

    Aber ansonsten, du hast sicher Boost, dann könntest du natürlich auch das folgende machen, wieder mit einem Beispielprogramm:

    #include <boost/xpressive/xpressive.hpp>
    
    #include <string>
    #include <iostream>
    
    bool is_integer(std::string const& text)
    {
    	using namespace boost::xpressive;
    
    	sregex r = bos >> !as_xpr('-') >> +_d >> eos;
    	return regex_match(text, r);
    }
    
    int main() 
    {
    	std::string line;
    	std::getline(std::cin, line);
    
    	while(line.compare("exit") != 0)
    	{
    		if(is_integer(line))		
    		{ std::cout << "Number!" << std::endl; }
    		else
    		{ std::cout << "NaN!" << std::endl; }
    
    		std::getline(std::cin, line);
    	}
    
    	return 0;
    }
    

    Edit: Eine Korrektur und mir kam noch eine kürzere Version in den Sinn :p

    bool is_integer(std::string const& text) 
    { 
    	long number; 
    	return (std::stringstream(text) >> number).eof(); 
    }
    

    Grüssli



  • Dravere schrieb:

    Wie glaubst du ist strtol intern aufgebaut? Wahrscheinlich mit mehr als 10 Zeilen. Solche Funktionen lagert man in eine Headerdatei aus und macht sie inline. Dann kann man sie immer wieder verwenden.

    strtol ist nämlich für deinen Fall völlig verkehrt. Du willst ja nicht die Zahl konvertieren, sondern nur feststellen, ob es eine Zahl ist. Genauso, wie die obige Lösung eigentlich verkehrt ist.
    Beim Programmieren sollte man nicht möglichst wenig Zeilen schreiben, dass ist der falsche Weg!

    Mir geht es ja nicht darum, um jeden Preis so viele Codezeilen wie möglich einzusparen. Aber in vielen Fällen ist die kürzere Variante eben auch die übersichtlichere und lesbarere. Natürlich kann ich sowas als Funktion in eine Header-Datei packen, aber warum sollte ich selbst großartig Code schreiben für Sachen, die sich ohne weiteres auch mit Funktionen aus den Standard-Libraries erledigen lassen? Zumal ich es ja mit großer Wahrscheinlichkeit auch nicht besser machen könnte.

    Dravere schrieb:

    Edit: Eine Korrektur und mir kam noch eine kürzere Version in den Sinn :p

    bool is_integer(std::string const& text) 
    { 
    	long number; 
    	return (std::stringstream(text) >> number).eof(); 
    }
    

    Sehr schön, gefällt mir :). Kurz und knapp. (und daß ich den Stream auf EOF testen muß, darauf hätte ich natürlich auch selbst kommen können).

    Was mir noch nicht ganz klar ist: Du sagst, daß das eigentlich "falsch" ist, weil ich den String ja nur testen und nicht umwandeln möchte. Aber wo ist dabei eigentlich das Problem? Performance ist (im Allgemeinen) kein gutes Argument, also was dann?
    Und vor allem... nehmen wir mal an, ich möchte jetzt nicht Integers überprüfen, sondern Floats. Mit find_first_not_of und Co. kommt man da nicht weit, und ein regulärer Ausdruck ist auch nicht mehr ganz trivial. Welche vernünftigen Alternativen zum Umwandeln per Stream o.ä. blieben da noch?



  • Dravere schrieb:

    Edit: Eine Korrektur und mir kam noch eine kürzere Version in den Sinn :p

    bool is_integer(std::string const& text) 
    { 
    	long number; 
    	return (std::stringstream(text) >> number).eof(); 
    }
    

    Schön - aber ich würde einen istringstream nehmen. Funktioniert zwar nicht anders als das Obige, aber irgendwie nehme ich lieber die Schnittstelle, die genau passt. 😉

    dooooomi schrieb:

    ...
    Was mir noch nicht ganz klar ist: Du sagst, daß das eigentlich "falsch" ist, weil ich den String ja nur testen und nicht umwandeln möchte. Aber wo ist dabei eigentlich das Problem? Performance ist (im Allgemeinen) kein gutes Argument, also was dann?...

    Ich kann zwar nicht wirklich für Dravere antworten, aber ich hätte dasselbe geschrieben (wenn auch evtl. aus anderen Gründen).
    Es ist guter Stil, möglichst exakt das zu programmieren, was man auch tun will und nicht, "von hinten durch die Brust ins Auge".
    Ich bin schon oft genug über sowas in fremdem Code gestolpert: "Warum wandelt der das denn in eine Zahl um ? Was macht der denn mit der Zahl ?" ... und dann fräst Du Dich durch 10.000 Zeilen Code - bloß um dann festzustellen, dass es ihm eigentlich nu darum ging, festzustellen, ob der Input eine Zahl ist, der Wert aber (in dieser Komponente) keine Rolle spielt.
    Gerne ist sowas dann mit wildem "Variablenreuse" gepaart.
    Mal ein Beispiel:

    void do_some_freaky_stuff(long&);
    
    long L;
    if(ss >> L)
    {
       do_some_freaky_stuff(L);
       calc_really_important_nasa_operation(L);
    }
    

    ... und dann findest Du nach 2 Tage Recherche in einem entlegenen Winkel des Projekts die Implementation:

    void do_some_freaky_stuff(long& L) {
       L = 17;
    };
    

    Hoppla - die Funktion nutzt ja den Parameter nur als output-Parmeter!!
    (kann man ja leider in C++ nicht von einem update-Parameter unterscheiden)
    Solchen Ärger kann man sich ersparen.

    Gruß,

    Simon2.


  • Administrator

    Simon2 schrieb:

    Schön - aber ich würde einen istringstream nehmen. Funktioniert zwar nicht anders als das Obige, aber irgendwie nehme ich lieber die Schnittstelle, die genau passt. 😉

    Stimme ich dir zu, war nur zu faul noch das i hinzuschreiben 🙂

    Auch mit deiner Erklärung bin ich absolut einverstanden. Vielleicht noch ein wenig ergänzend in eigenen Worten:
    Man sollte zu einem Problem eine genaue Lösung liefern und nicht probieren eine andere Lösung umzubiegen, damit sie passt. So ein Vorgehen ist zum einen fehleranfällig und zum anderen für andere Leser des Codes nur sehr schwer verständlich.
    Zudem, aber das sei jetzt wirklich nur als zusätzliche und nebensächliche Notiz gesagt, ist die Effizient des ausgeführten Codes schlecht.

    Am wichtigsten empfinde ich allerdings, was man dabei lernt. Wenn man Probleme immer wie mehr anfängt zu lösen, indem man andere Lösungen umbiegt, gewöhnt man sich einen schlechten Stil an. Es geht halt in der Programmierung oft um Gewohnheiten, da man Dinge immer wiederholt. Es ist daher das beste, wenn man sich das Gegenteil angewöhnt, also so wenig bis nie eine Lösung umbiegt.

    Grüssli



  • Ich kann euch beiden da gar nicht wiedersprechen, prinzipiell bin ich ja eurer Meinung. Aber nichtsdestotrotz, so wie ich das sehe macht strtol 2 Dinge; es wandelt einen String in ein Integer um, und es prüft ob es sich bei dem String überhaupt um eine ganze Zahl handelt (und für den istringstream oder evtl. auch sowas wie boost::lexical_cast gilt das selbe).

    So gesehen wird die Funktion ja nicht zweckentfremdet, sondern sie macht einfach ein kleines bißchen mehr als nötig. Daß der "Rückgabewert" nicht weiter benutzt wird ist sicherlich eine Sache, die man durch einen Kommentar oder zumindest die Benennung der Variable klarmachen sollte. Und letztlich ging es in meinem Ursprungs-Post ja genau um die Frage, wie ich an der Stelle um eine unnütze Dummy-Variable herumkomme.

    Meine letzte Frage (Erkennung von float ohne Umwandlung) habt ihr übrigens beide nicht beantwortet 🙂


  • Administrator

    dooooomi schrieb:

    Meine letzte Frage (Erkennung von float ohne Umwandlung) habt ihr übrigens beide nicht beantwortet 🙂

    Weil sie so trivial ist und man auch mit den String-Funktionen genausoweit kommt.

    bool is_float(std::string const& text)
    {
      if(text.size() == 0)
      { return false; }
    
      std::string::size_type index = 0;
    
      if(text[0] == '-')
      { index = 1; }
    
      index = text.find_first_not_of("0123456789", index);
    
      if(index != std::string::npos && text[index] == '.')
      { index = text.find_first_not_of("0123456789", index + 1); }
    
      return index == std::string::npos;
    }
    

    Und ein Regex sähe auch nicht so gross aus, über Boost geht das ganz einfach. Zudem sollten die Regulären Ausdrücke im nächsten Standard enthalten sein.

    Zum Rest kann ich nichts mehr dazufügen. Ich habe gesagt wie ich es sehe und Simon auch. Die Funktion ist zur Umwandlung gedacht, den Syntaxcheck erfolgt logischerweise automatisch. Wenn du die Funktion zur Umwandlung nur als Syntaxcheck missbrauchst, dann ist das eine Zweckentfremdung in meinen Augen.
    Wir können dir allerdings nur Tipps geben, was du schlussendlich machst, das kannst nur du entscheiden. Wenn du die Tipps nicht befolgen willst, dann lern es eben selber. Es geht gut, bis es schief geht. 🙂

    Grüssli



  • Das geht aber schief wenn die Zahl in der Exponentialschreibweise da steht. Also evtl. noch auf e E und + testen.



  • OMG, mit RegEx oder simplen Stringfunktionen zu prüfen, ob ein String eine Zahl ist, ist ein dirty hack. Ist "1,001" eine ganze Zahl? Ist "٠" es?
    Es ist ein größer Aufwand, das herauszufinden, also spart es euch und nutzt die vorhandenen Mechanismen.



  • Dravere schrieb:

    dooooomi schrieb:

    Meine letzte Frage (Erkennung von float ohne Umwandlung) habt ihr übrigens beide nicht beantwortet 🙂

    Weil sie so trivial ist und man auch mit den String-Funktionen genausoweit kommt.

    Erkennt dein Code auch Floats in Exponent-Schreibweise? Floats mit vorangestelltem "+"? "inf" und "nan"?

    Natürlich, die Sachen kann man alle noch einbauen. Aber als trivial würde ich das nicht mehr bezeichnen. Der Punkt ist, über all diese Dinge hat sich schonmal jemand Gedanken gemacht, und es gibt gut funktionierende und tausendfach getestete Funktionen dafür in der Standard-Library. Warum sollte eine selbstgebastelte Lösung besser sein?

    Und das nächste Mal kommt jemand daher, stellt die Locale des Programms auf Deutsch um, und plötzlich ist das Dezimaltrennzeichen das Komma und nicht mehr der Punkt. Für stringstream und strtof kein Problem...


Anmelden zum Antworten