Stdargs mit dynamischem String



  • 1. Ich frag hier wegen den C-Funktionen für die stdargs und nicht wegen new und delete.
    2. char* text = new char; allokiert nicht nur 1 Zeichen.
    3. Ich will ja gerade einen virtuell unbegrenzt langen String schreiben können, da bringt mir ja malloc nichts.



  • Dr. C++ schrieb:

    2. char* text = new char; allokiert nicht nur 1 Zeichen.

    Na dann. 🙄

    Und es gibt keinen virtuell unbegrenzten String. Irgendwann ist Schluss, spätestens, wenn der RAM voll ist und möglicherweise noch die Auslagerungsdatei und den Speicher musst du erstmal allocaten, bevor du ihn verwenden darfst. Kein Wunder, dass deins nicht funzt.



  • Dr. C++ schrieb:

    1. Ich frag hier wegen den C-Funktionen für die stdargs und nicht wegen new und delete.
    2. char* text = new char; allokiert nicht nur 1 Zeichen.
    3. Ich will ja gerade einen virtuell unbegrenzt langen String schreiben können, da bringt mir ja malloc nichts.

    *lol*

    1. Hier wegen new und delete fragen wäre auch ziemlich dämlich
    2. Stimmt, nicht nur eins, in ANSI C sogar gark-eins...
    3. genau, auf keinen Fall malloc oder gar schlimmer realloc verwenden!

    *scnr*

    Greetz, Swordfish



  • feigling schrieb:

    Und es gibt keinen virtuell unbegrenzten String. Irgendwann ist Schluss, spätestens, wenn der RAM voll ist und möglicherweise noch die Auslagerungsdatei und den Speicher musst du erstmal allocaten, bevor du ihn verwenden darfst. Kein Wunder, dass deins nicht funzt.

    Na dann hab ich wohl Glück, dass folgender Code ohne Mucken funktioniert?

    char* text = new char;
    sprintf(text, "Hallo Welt!");
    cout << text;
    

    Gibt es jetzt abgesehen davon eine Möglichkeit, die stdargs mit einer unbestimmten Stringlänge zu kriegen? Der ganze Code ist nämlich für eine Log-Funktion, bei der über die stdargs die Ausgabe wie mit printf formatiert werden kann.



  • Dr. C++ schrieb:

    feigling schrieb:

    Und es gibt keinen virtuell unbegrenzten String. Irgendwann ist Schluss, spätestens, wenn der RAM voll ist und möglicherweise noch die Auslagerungsdatei und den Speicher musst du erstmal allocaten, bevor du ihn verwenden darfst. Kein Wunder, dass deins nicht funzt.

    Na dann hab ich wohl Glück, dass folgender Code ohne Mucken funktioniert?

    char* text = new char;
    sprintf(text, "Hallo Welt!");
    cout << text;
    

    Verlass dich besser nicht darauf, daß das funktioniert - du hast nur Platz für ein char angefordert, das bedeutet, daß der Rest des Strings in fremden Speicherbereichen landen wird (mit Glück würde sich das Programm sofort beschweren, aber typischerweise taucht der Fehler in einem Programmteil auf, der gar nichts mit diesem Fragment zu tun hat).

    Gibt es jetzt abgesehen davon eine Möglichkeit, die stdargs mit einer unbestimmten Stringlänge zu kriegen? Der ganze Code ist nämlich für eine Log-Funktion, bei der über die stdargs die Ausgabe wie mit printf formatiert werden kann.

    Nicht wirklich. Du könntest nur vorsorglich mehr Speicher anfordern und hoffen, daß der ausreicht*. (MFC's CString hat eine Methode 'Format()', die printf-Formatierungen vornimmt. Aber frag mich nicht, wie diese Methode arbeitet)

    * Zur Abschätzung kannst du den Formatstring durchgehen und alle %... Sequenzen untersuchen - bei den meisten Formaten kannst du eine Obergrenze für die Länge angeben. (atm fällt mir nur %s ein, das Probleme bereiten könnte)



  • Dr. C++ schrieb:

    Gibt es jetzt abgesehen davon eine Möglichkeit, die stdargs mit einer unbestimmten Stringlänge zu kriegen? Der ganze Code ist nämlich für eine Log-Funktion, bei der über die stdargs die Ausgabe wie mit printf formatiert werden kann.

    hast du _vsnprintf' ?
    dann könntestes so machen

    #include <stdio.h>
    #include <stdarg.h>
    
    #define BUFFERSIZE 20
    void log (char *fmt, ...)
    {
      char buff[BUFFERSIZE];
      va_list args;
    
      va_start (args, fmt);
      _vsnprintf (buff, BUFFERSIZE, fmt, args);
      va_end (args);
    
      // ausgabe
      puts (buff);
    }
    
    int main (void)
    {
       log ("hello %d", 1234);
       log ("diese zeile ist eindeutig zu lang");
    }
    


  • Und wenn wir schon die plattformabhängigen Kisten rauskramen, gibt's da auch noch vasprintf:

    void log (char *fmt, ...)
    {
      char* buff;
      va_list args;
    
      va_start (args, fmt);
      vasprintf (&buff, fmt, args);
      va_end (args);
    
      // ausgabe
      puts (buff);
    
      free(buff);
    }
    


  • @ten: bei deinem Code ist die Größe ja schon wieder begrenzt.
    @LordJaxom: irgendwie kennt mein Kompiler vasprintf nicht?!



  • Dr. C++ schrieb:

    @ten: bei deinem Code ist die Größe ja schon wieder begrenzt.

    du kannst ja auch BUFFERSIZE auf 0xffff setzen.
    so lange zeilen brauchst du doch gar nicht, kann ja keiner mehr lesen 😉



  • Loooool, das würde ich machen, wenn ich nen Stackoverflow oder nen vollen Arbeitsspeicher haben wöllte.



  • Dr. C++ schrieb:

    Loooool, das würde ich machen, wenn ich nen Stackoverflow oder nen vollen Arbeitsspeicher haben wöllte.

    na also,
    dann mach den buffer 'static' und 256 bytes gross.
    das sollte doch reichen...
    🙂



  • ten schrieb:

    Dr. C++ schrieb:

    Loooool, das würde ich machen, wenn ich nen Stackoverflow oder nen vollen Arbeitsspeicher haben wöllte.

    na also,
    dann mach den buffer 'static' und 256 bytes gross.
    das sollte doch reichen...
    🙂

    Ich frag hier, wie ich stdargs mit unbegrenzter Länge kriegen kann und nicht wie ich einen Buffer anlege, diesen als static deklarieren und 256 Bytes klein lasse 😕 . Die Logs werden nicht gerade mit kurzen Messages gefüllt und ich weißt nicht, ob static unbedingt sehr threadsicher ist.



  • Wie schon mehrfach gesagt wurde, kannst du das nicht mit Standard-Mitteln - zumindest kenne ich keine Funktion, die a-priori die Länge der printf()-Ausgabe berechnet. Also bleiben dir nur die Möglichkeiten, die Länge abzuschätzen (mit der geringen Chance, trotzdem zu wenig Speicher zu haben), mehrfach mit wachsenden Speichergrößen Anlauf zu nehmen (wenn's nicht geklappt hat, holst du dir etwas mehr Speicher und rufst vnsprintf() nochmal auf) oder den Formatstring selber zu parsen (und dir quasi ein printf()-Derivat für std::string zu bauen*).

    * Da wäre eventuell Boost::Format eine Lösungsmöglichkeit.



  • Dr. C++ schrieb:

    Ich frag hier, wie ich stdargs mit unbegrenzter Länge kriegen kann

    die frage wurde schon beantwortet: das gibt es nicht.

    Dr. C++ schrieb:

    Die Logs werden nicht gerade mit kurzen Messages gefüllt und ich weißt nicht, ob static unbedingt sehr threadsicher ist.

    der pufferinhalt muss ja nur so lange gültig sein, bis die message weggeschrieben wurde. also machste den buffer so gross wie eine lange message sein kann, _vsnprintf verhindert einen overflow, ein 'lock' am angang der funktion und ein 'unlock' am ende. und schon kann der nächste thread seine message loswerden...



  • Und was hat dann LordJaxom mit seinem letzten Post und der Funktion vasprintf gemeint?



  • Da ten auch nicht erwähnt hat dass _vsnprintf ne MS-Erweiterung ist, habe ich mir erlaubt zu unterschlagen, dass vasprintf eine GNU-Erweiterung ist. Ist also nur unter Linux und möglicherweise noch mit dem MinGW-Compiler für Windows verfügbar.


Anmelden zum Antworten