string ist bei Ausgabe mit printf (null)



  • Ah, danke!

    string hallo = "ichbineinstring";
    char str[20] = "ichbinaucheinstring";
    printf("%s",str);
    printf("\n");
    cout << hallo << endl;
    getchar();
    

    So ist besser 🙂



  • PeterFragt schrieb:

    Ah, danke!

    string hallo = "ichbineinstring";
    char str[20] = "ichbinaucheinstring";
    printf("%s",str);
    printf("\n");
    cout << hallo << endl;
    getchar();
    

    So ist besser 🙂

    nicht wirklich...

    using namespace std;
    
    const char str[] = ".....";
    cout << str << endl;
    

    bb



  • Ja. Und da es normalerweise keinen Grund gibt, sich mit printf() rumzuschlagen, kannst du auch für char* den C++-Stream std::cout nehmen. Dieser funktioniert nämlich genauso und erkennt im Gegensatz zu printf() seinen Argumenttyp, du brauchst also kein "%s" .



  • Verstehe, danke!



  • Und falls du doch mal für irgendeine Funktion einen char* auf deinen std::string brauchst (soll schon mal vorkommen), dann nimm wie gesagt die Methode c_str, also "hallo.c_str()" (so würde es auch mit printf klappen)...



  • ich behalts im Hinterkopf



  • string z = "lutsch0r!";
    	printf( "%s", z.c_str());
    


  • PeterFragt schrieb:

    ich behalts im Hinterkopf

    aber behalts mit const char* und nicht char* im hinterkopf ^^
    braucht man aber eigtl nur für C-APIs

    bb



  • unskilled schrieb:

    braucht man aber eigtl nur für C-APIs

    Nö. Wie konstruierst du z.B. ein std::fstream-Objekt? 😉
    (In der Praxis benutzt man std::fstream natürlich nach Möglichkeit ohnehin nicht.)



  • audacia schrieb:

    ...

    hab ja extra "eigentlich" geschrieben - ist ja nicht so, dass ich nicht daran gedacht hätte 😉 danke ^^

    bb



  • Manchmal hat man ja auch mit C-APIs (oder C++-APIs, die trotzdem C-Strings verwenden) zu tun. Kann man sich nicht immer aussuchen, daher ist es auch gut, zu wissen was man in dem Fall mit seinen std::string's machen muss...



  • audacia schrieb:

    Nö. Wie konstruierst du z.B. ein std::fstream-Objekt? 😉

    Das sollte doch im kommenden Standard angepasst werden.

    audacia schrieb:

    (In der Praxis benutzt man std::fstream natürlich nach Möglichkeit ohnehin nicht.)

    Wie?



  • Nexus schrieb:

    audacia schrieb:

    (In der Praxis benutzt man std::fstream natürlich nach Möglichkeit ohnehin nicht.)

    Wie?

    Na du solltest natürlich fprintf/fscanf benutzen! Wusstest du das etwa nicht? 😉 😃



  • Nexus schrieb:

    audacia schrieb:

    (In der Praxis benutzt man std::fstream natürlich nach Möglichkeit ohnehin nicht.)

    Wie?

    Nun, die Streams sind in allen mir bekannten Implementationen langsamer als C-Streams (teilweise um Größenordnungen), und außerdem sind sie nicht moduslos, was Fehler in der Anwendung begünstigt und den korrekten Umgang massiv erschwert. Gewöhnlich ist man mit einem kleinen RAII-Wrapper um die C-Funktionen viel besser dran.



  • Okay, das kann gut sein, ich kenne die C-Funktionen aber auch zu wenig, um das genau beurteilen zu können.

    Naja, ich hatte bisher eigentlich nicht viele Probleme mit std::fstream , für meine Anwendungen reicht es. Ich finde zum Beispiel auch die Operatoren >> und << sehr komfortabel und habe momentan nicht wirklich Lust, alle Überladungen nachzuprogrammieren. 😉



  • Nexus schrieb:

    Okay, das kann gut sein, ich kenne die C-Funktionen aber auch zu wenig, um das genau beurteilen zu können.

    Man braucht die C-Funktionen nicht zu kennen, um zu sehen, daß es sich bei fstream um einen gewaltigen Designfehler handelt. Beispiele: die Existenz von fstream::good() und fstream::close().



  • audacia schrieb:

    Man braucht die C-Funktionen nicht zu kennen, um zu sehen, daß es sich bei fstream um einen gewaltigen Designfehler handelt. Beispiele: die Existenz von fstream::good() und fstream::close().

    Ja, die Streams sind zum Teil etwas speziell. Allerdings habe ich die bisher nicht so kritisch betrachtet, was auch daran liegen könnte, dass ich kaum Alternativen kenne.

    Aber weshalb erachtest du die beiden Methoden als Designfehler? Weil sie durch andere Memberfunktionen eigentlich bereits abgedeckt sind (z.B. Dtor bei close() )?


  • Administrator

    audacia schrieb:

    Nun, die Streams sind in allen mir bekannten Implementationen langsamer als C-Streams (teilweise um Größenordnungen), und außerdem sind sie nicht moduslos, was Fehler in der Anwendung begünstigt und den korrekten Umgang massiv erschwert.

    1. Geschwindigkeit:
    http://www.cplusplus.com/reference/iostream/streambuf/pubsetbuf/
    Viele Implementationen haben standardmässig keinen Puffer gesetzt, weshalb sie als deutlich langsamer erscheinen. Der Puffer kann verdammt viel ausmachen.

    2. Moduslos:
    http://www.cplusplus.com/reference/iostream/ios/exceptions/
    Man kann sich über Modusänderungen sehr schnell und explizit informieren lassen.

    Grüssli



  • Nexus schrieb:

    Aber weshalb erachtest du die beiden Methoden als Designfehler?

    fstream::good(), weil es impliziert, daß ich stets manuell auf Fehler überprüfen muß. Wozu gibt es denn Exceptions?

    fstream::close(), weil es das Objekt in einen Modus versetzt, in dem der Aufruf mancher Methoden nicht mehr gültig ist. Zudem steckt fstream noch in einer Vererbungshierarchie, in der es auf diese Weise das LSP verletzt.

    Dravere schrieb:

    2. Moduslos:
    http://www.cplusplus.com/reference/iostream/ios/exceptions/
    Man kann sich über Modusänderungen sehr schnell und explizit informieren lassen.

    Das ist nicht, was ich mit "moduslos" meine; siehe meine Ausführungen zu fstream::close().

    Und daß man das Verhalten im Fehlerfalle umstellen kann, macht die Sache IMHO nur noch schlimmer, weil man dadurch ein fstream-Objekt mit noch einem Zustand behaftet, der ihn eigentlich nichts angeht. Beispiel:

    void tryRead (istream& stream, ...)
    {
        stream.read (...);
        if (!stream.good ())
            ...; // set default value
    }
    void foo (void)
    {
        std::fstream theFile ("someFile", ...);
        theFile.exceptions (>alles<);
        ...
        tryRead (stream, ...); // <--
    }
    

    Hier verursacht der Aufruf von tryRead() unerwartetes Verhalten, da tryRead() sich auf das Standardverhalten des Streams verläßt. Korrekt müßte man tryRead() also so implementieren:

    class StreamExceptionStatePreserver
    {
    private:
        ios_base::iostate prevState;
    public:
        StreamExceptionStatePreserver (ios& theStream, ios_base::iostate newState)
         : prevState (theStream.exceptions ())
        { theStream.exceptions (newState); }
        ~StreamExceptionStatePreserver (void)
        { theStream.exceptions (prevState); }
    };    
    
    void tryRead (istream& stream, ...)
    {
        StreamExceptionStatePreserver esp (stream, >garnix<);
        stream.read (...);
        if (!stream.good ())
            ...; // set default value
    }
    

    Ich weiß nicht, wie es dir geht, aber spätestens da schreit sämtliche mir verbliebene Intuition laut "Designfehler".

    Eine Klasse, die derartige Workarounds erfordert, wird von mir i.d.R. ohnehin erst von einem adäquaten Wrapper umgeben, der die Komplexität in der Anwendung reduziert. Und wenn wir ohnehin beim Wrappen sind, können wir auch gleich die C-Funktionen wrappen, weil sie viel weniger Ballast haben und in der Praxis schlicht schneller sind, Puffer hin oder her.


  • Administrator

    @audacia,
    1. Wieso verletzt fstream das Liskovsches Substitutionsprinzip? Leuchtet mir gerade nicht ein.
    2. Bei den Exceptions setze ich immer den richtigen Status für das Programm oder Bibliothek gleich beim Anfang der Arbeit. Also wenn ein Stream übergeben wird, dann hole ich mir das streambuf Objekt raus und übergebe es einem eigenen Streamobjekt.
    3. Das mit der Geschwindigkeit verstehe ich nicht. Ich habe schon selber Tests durchgeführt und zwar mit einer XML Bibliothek. Allerdings muss ich sagen, dass meine XML Files sich in Grössenordnungen von 1 - 2 MiB bewegt haben. Ich konnte keinen Unterschied messen. Was für mich bedeutet, dass es wahrscheinlich erst bei wirklich grossen Files unter Umständen zu einer Differenz kommt. Und wahrscheinlich ist die Differenz eher klein. In den meisten Fällen ist die "Anklage" allerdings völlig übertrieben.
    4. Wenn man wirklich etwas an den Streams ankreiden möchte, dann sollte man dies beim ganzen Locale und Facet Zeug machen. Dort ist meiner Meinung nach wirklich ein Designfehler passiert. Das Zeug ist viel zu komplex, es verstösst gegen Speicherzugehörigkeit (wer Speicher holt, gibt ihn frei), ist unübersichtlich und unverständlich, viel zu umfangreich für kleine Dinge, usw. usf.

    5. Gibt es eigentlich Vorschläge für Verbesserung der Streams? Bzw. gibt es einfachere/bessere Streambibliotheken? Wäre mal interessant sich mit dem Zeug auseinander zu setzen.

    Grüssli


Anmelden zum Antworten