sprintf-Alternative für C++ strings

  • Hi!


    Mal ne bölde Frage: Gibt es eigentlich eine sprintf (usw.)-Aternative für std::string? std::string ist ja recht praktisch in Listen usw. zu verwenden und man braucht sich nicht um die Länge zu kümmern, aber das praktische sprintf und snprintf scheint es da ja nicht zu geben oder?
    Ohne die ist es aber auch nicht so wirklich praktisch, denn dann ist das Zusammensetzten von Strings irgendwie viel unkomfortabler ...


    Gibts da doch was, oder muss ich den Umweg über einen Dummy-C-String gehen?


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

  • Der offizelle Weg sieht eigentlich so aus :


    Code
    std::ostringstream os;
    
    
    os << " Das ist der " << x << " Durchlauf" << std:endl << std::ends;
    
    
    std::string s = os.str();


    Dabei kann "x" jeder Datentyp oder Klasse mit eigenen operator << () sein,
    hier sehe ich den Vorteil. Gerade wenn mit Überladungen gearbeitet wird.
    Vorteil ist die Typsicherheit der Ausgabe, Nachteil der höhere Schreibaufwand.


    Die Ausgabe per ostream erschwert aber gelegentlich die Lokalisierung, diese geht mit sprintf bzs. asprintf doch leichter...


    Andreas

  • Hi!


    Danke für die Info. Das kannte ich wirklich noch nicht. Irgendwie ist es aber wirklich schade dass die printf-Syntax da verloren geht.
    Ich habe öfters VB und VBA programmiert und da muss man auch alles mit "&" zusammenwursteln ... da fehlte mir eigentlich diese printf-Syntax. Werde wohl doch den Weg über snprintf gehen.


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

  • Der Vorteil von ostream abgeleiteten Klassen ist man kann es als String, Stdout oder Dateiausgabe verwenden, in dem nur eine Funktion verwendet wird :



    Sollte unter anderem eine Stdout Ausgabe machen, und eine Datei test.txt erstellen...
    und diesen Text am String zur Ververfügung stellen...


    X=1 Y=2
    X=3 Y=4
    X=5 Y=6

  • Übrigens gibt es für Streams auch "Modifikatoren":


    z.B.


    os << hex << set_w(5) << set_fill('0') << 23;


    kodiert in hex, macht die Zahl 5 Zeichen lang und füllt vorne mit Nullen auf.


    dafür brauchts dann ein #include <iomanip> und ist m.M. nach eine sehr schöne elegante Art und Weise, zu kodieren.


    printf und Verwandte haben in einem C++-Programm nichts zu suchen, zumal der ganze Mist keineswegs threadsafe ist da zuhauf statischer Speicher für die Rechnerei verwendet wird.


    -> auf einem HT-Prozessor oder SMP-System musst du bei multithreaded applikationen da jedesmal eine semaphore drumrumbatschen. Das ist *örrglll*

    This is a .44 Magnum, the most powerful handgun in the world. It can take your head clean off. You've got to ask yourself one question, Do I feel lucky?
    easyvdr 0.9a2 - TT-DVB-S2-6400 - ASUS AT3IONT-I deluxe - Atom 330 - 1,5TB WD EADS - Denon 1910 - Toshiba 42X3030D - Harmony 700

  • Sinn der stringstreams ist ja durch Aufhebung der Trennung von Format-String und Parametern Typsicherheit zu erreichen. Bei C musste sich die Bibliothek drauf verlassen, dass der Benutzer bei %s als nächsten Parameter ein const char* liefert. Bei Stringstreams weiss die Sprache bereits den Typ, kann einen entsprechenden operator<< aufrufen, wenn es den nicht gibt kommt es schon zu einem Compile-Fehler.


    Wer trotzdem nicht auf die Formatstrings verzichten möchte dem sei boost::format ans Herz gelegt:


    Code
    cout << format("%.2f + %.2f = %.2f") % 2 % 2.2 % 4.2;


    oder


    Code
    cout << format("Hallo, %1%! Wie geht es %2% heute?") % username % (alter > 18 ? "Ihnen" : "Dir");
  • Hi!


    Danke für die erweiterten Infos. Ev. gewöhne ich mich ja mal um ... mal sehen. Ich denke aber bei meinem Coding-Style ist es auch schon egal wenn ich diesen "Fehler" auch noch mache. ;D


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -



  • *hust* *hust*


    Dann schauen wir uns mal das Vorzeigeobjekt an :D


    vdrserver VDR # cd /usr/local/src/VDR
    vdrserver VDR # grep "stream" *.c | wc
    27 193 1954
    vdrserver VDR # grep "print" *.c | wc
    193 1643 16245
    vdrserver VDR # grep "cout" *.c | wc
    0 0 0


    Aber ich bin auch relativ flott auf cout anstat printf umgestiegen. Ich finde es ist angenehmen zu lesen und man kann viel schneller wechseln ob ich in die stdout, in einen String oder in eine Dateischreiben möchte. Außerdem sind die Formatierungsmöglichkeiten auch angenehmer und ersichtlicher....


    Mfg
    Ulrich

    Aktuelle Systeme:
    VDR-Server: MSI KT6A Ultra FISR ; Athlon XP 2200+ ; GrKa Geforce 2 MX; 256MB DDR-SDRam Plugins: streamdev-server, remote
    2 x DVB-Budget Karte, Gentoo, Kernel 2.6.8 usw....

  • Ich glaube nicht, dass VDR das C++-Vorzeigeobjekt ist ;)


    Bins halt noch gewohnt von meiner Diplomarbeit (Netzwerkprotokollinstanz unter Linux, multi-threaded und in C++), da wurde mir jedes fprintf (zurecht) um die Ohren gewatscht ;)

    This is a .44 Magnum, the most powerful handgun in the world. It can take your head clean off. You've got to ask yourself one question, Do I feel lucky?
    easyvdr 0.9a2 - TT-DVB-S2-6400 - ASUS AT3IONT-I deluxe - Atom 330 - 1,5TB WD EADS - Denon 1910 - Toshiba 42X3030D - Harmony 700

  • Zitat

    Original von Morone


    ..mach das mal mit dem burn-plugin ;)


    habe ich nicht *ätschipädschi* (oder wie schreibt man das?)

    Aktuelle Systeme:
    VDR-Server: MSI KT6A Ultra FISR ; Athlon XP 2200+ ; GrKa Geforce 2 MX; 256MB DDR-SDRam Plugins: streamdev-server, remote
    2 x DVB-Budget Karte, Gentoo, Kernel 2.6.8 usw....

  • Sacht ma, ihr string und stream Meister: Ich finde es absolut lästig und auch nicht besonders lesbar mit für jeden formatierten string, den ich mir zusammenbasteln will, ein ostringstream Objekt anlegen und das über drei Zeilen verteilen zu müssen. Gerade beim Werfen von Exceptions sehr unhandlich. Kann man sowas nicht in eine Zeile quetschen, a la
    runtime_error((ostringstream() << "Device '" << szDev << "' (" << nDev << ") not accessible...).str().c_str())
    ? Sieht so ziemlich scheisse aus und geht so auch net, aber klar, worauf ich hinaus will?

    yaVDR 0.6.2; H61M/U3S3 / G530 / 4GB / GT 520 (passiv) / Cine S2 (Rev. V5.5) + DuoFlex S2 / 120GB SSD (System; SATA>USB) + 3TB SATA 6Gb/s; LCD-TV Toshiba 42VL863G; AVR Yamaha RX-S600...

  • Ich habe mich mit dem Thema auch beschäftigt. Da ich boost zu dem Zeitpunkt noch nicht kannte, habe ich mir ein Objekt gebaut, das eine "printf"-ähnliche Formatierung erlaubt, typensicher ist und für die Internationalisierung taugt.


    Syntax ist ungefähr so:


    Code
    Object text("Ich formatiere mit %1% und %2%...");
    text << wasimmerdasist << wasanderes;


    Die Prozentzeichen werden als Positionierer genutzt und enthalten nur die Formatanweisungen für die Länge, Rechts/Linksbündigkeit und Genauigkeit. Da anschließend über den Operator "<<" das eigentliche Objekt eingebaut wird, habe ich keine Probleme mit den Datentypen. Die Verwendung von Zahlen ermöglicht die Neuordnung im Text ohne den Code umbauen zu müssen.


    "printf" ist meiner Meinung nach schon threadsafe. Man darf halt nicht die singlethread Variante nehmen, die dafür schneller ist. Eindeutiges Killerargument ist aber die Typenlosigkeit. Auch kann man leicht durch Fehlimplementierung schöne Angriffsflächen in sein Programm einbauen. Von daher gefallen mir die Streams aus der STL schon deutlich besser.


    Achja, vdr ist wahrlich kein Vorzeigeprojekt für C++. Eigentlich ist es im grossen und ganzen C mit Objekten. Aber das ist ein anderes Thema. Ich freue mich, das es trotzdem funktioniert.

  • dierk
    Also, ich meinte schon eine einfache Lösung auf Basis des C++ Sprach- bzw. Standardbibliotheksumfangs. Narürlich kann man sich immer was angenehmes dazu basteln, nur muss sich da ein Dritter ja immer esrt reindenken...

    yaVDR 0.6.2; H61M/U3S3 / G530 / 4GB / GT 520 (passiv) / Cine S2 (Rev. V5.5) + DuoFlex S2 / 120GB SSD (System; SATA>USB) + 3TB SATA 6Gb/s; LCD-TV Toshiba 42VL863G; AVR Yamaha RX-S600...

  • Was hindert dich am ziemlich scheisse aussehenden


    Code
    throw runtime_error( (ostringstream() << "hallo " << 12).str() );


    ? Klappt wunderbar. (.c_str() ist nat. quatsch da runtime_error ein string nimmt)


    Zitat

    ..mach das mal mit dem burn-plugin Augenzwinkern


    Aber erst ab 0.1.0-pre4 bitte :P und schick mir dann alle Fälle damit ich sie beseitigen kann ;D


    dierk: In burn ist auch so ein Hilfsobjekt zum formatieren drin, habe aber {n} als Platzhalter ;)

  • Zitat

    Original von LordJaxom
    Was hindert dich am ziemlich scheisse aussehenden


    Code
    throw runtime_error( (ostringstream() << "hallo " << 12).str() );


    Also z.B. zu

    Code
    string s = (ostringstream() << "hallo " << 12).str();


    sagt mein Compiler niente (str sei nicht definiert)!

    yaVDR 0.6.2; H61M/U3S3 / G530 / 4GB / GT 520 (passiv) / Cine S2 (Rev. V5.5) + DuoFlex S2 / 120GB SSD (System; SATA>USB) + 3TB SATA 6Gb/s; LCD-TV Toshiba 42VL863G; AVR Yamaha RX-S600...

  • Oh, hast recht (mea culpa), habs im falschen Kontext ausprobiert ?( liegt daran dass operator<< ein ostream und kein ostringstream zurückgibt...


    Also doch boost::format oder etwas selbstgeschriebenes... Oder man lagert sich das Stringstream-Gewurstel in ne kleine Funktion aus und benutzt sonst Stringkonkatenation. Beispiel:


  • LordJaxom
    Also doch wieder was handgeschnitztes, in das sich ein Dritter erst reindenken muss. Ich verstehe das gerade bei der String-Verarbeitung nicht, die ja nun wirklich in fast jedem Progi benötigt wird...

    yaVDR 0.6.2; H61M/U3S3 / G530 / 4GB / GT 520 (passiv) / Cine S2 (Rev. V5.5) + DuoFlex S2 / 120GB SSD (System; SATA>USB) + 3TB SATA 6Gb/s; LCD-TV Toshiba 42VL863G; AVR Yamaha RX-S600...

  • In meinem Beispiel habe ich absichtlich einen mehrschrittigen Vorgang dargestellt. Man kann diese Schritte durchaus verstecken. Dies wollte ich hier aber absichtlich nicht tun.


    Nochmal eine kurze Erklärung zu den Zeilen.


    1. Instanziierung:
    Object text("%1:02% Das sind %2:4.2% %% der Kapazität von %3% GB.");
    Noch nicht schwer zu erraten: das Objekt wird angelegt und bekommt im Konstruktor den passenden Text mitgeliefert. Wo der herkommt ist eigentlich egal. Die Syntax erinnert an printf, es gibt jedoch keine Typenangabe, da der Compiler den Typ der Variablen selber kennt.


    text << wert1 << wert2 << wert3;
    Jetzt nur noch die Daten reinpumpen.


    (Das hat vorher gefehlt:)
    outstream << text;
    fertig oder auch
    string result = text;


    Die ganzen Formatanweisungen (left/right; setw(x); fill('X') usw) sind in dem Objekt versteckt. Da ich für die Reihenfolge die Parameternummer festlegt habe, kann man die Werte zur Internationalisierung im Text umsortieren und muß den Quellcode nicht anfassen oder merkwürdige Formulierungen nehmen.


    Damit habe ich aus meiner Sicht das größte Problem der Streams gelöst. Die umständliche Handhabung der Formatierung in Ausgaben.
    Normalerweise würde das so aussehen*:

    out << fill('0') << setw(2) << std::right << wert1 << " Das sind " << fill(' ') << precision(2) << setw(4) << wert2 << "% der Kapazität von " << setw(0) << wert3 << " GB.";


    Und das war nur die Variante mit dem deutschen Text.


    *) Ich habe das gerade mal aus dem Kopf gemacht. Daher wird ein Compiler wahrscheinlich nicht zufrieden sein.

  • Hi Brougs78,


    es gibt noch andere Vorteile als die bereits genannten. Der größte Vorteil ist, dass du dich nicht mehr um die Speicherverwaltung und die Teminierung der Zeichenketten kümmern musst. Es mag sein, dass du ein paar Zeilen mehr tippen musst, aber die Zeit hast du locker wieder raus, wenn du auch nur einmal nach einem Fehler wegen z. Bsp fehlender Terminierung suchen musst.


    Oder du hast sowas:

    Code
    printf("%d", (time_t) t);


    Auf einer 32bit Intel Maschine wird das funktionieren, aber was ist, wenn du den Code auf ein anderes System portieren musst (z. Bsp. Alpha)?


    Mach dir die Mühe mit der Standardlib, das spart dir eine Menge Kaffee während des Debuggens.


    Viele Grüße
    KdF

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!