Gibt es eine sprintf ähnliche Funktion für std::string ???
-
Aber die Reihenfolge der Wörter! Wie löst Du das, wenn die Satzstellung in ner Sprache anders ist? Wenn Du den Text auf mehreren Sprachen pflegst und über %text1 halt die Positionen der einzufügenden Begriffe wählen kannst, passt das. Bei Streams ist aber die Stellung der variablen Texte fixiert.
Bei Streams müsste man einen Vermittler bauen, der einen gestreamten Text erkennt, weiß, was davon dynamisch ist, und es entsprechend verdreht, wenn die Sprache geändert wird. Äußerst aufwendig. Es sei denn, man hängt halt wieder einen String rein, der nochmal analysiert und umgeschmissen wird, aber dann ist das ja keine wirkliche Stream-Lösung.
Hm... Oder man baut einen ganz neuen Stream, bei dem die Reihenfolge der Elemente von vornerein geändert wird. Beispielsweise hätten wir eine Logik, dass:
("Text1" "Variable" "Text2") auf Deutsch in der Reihenfolge 123 stehen, auf Englisch in der Reihenfolge 231.
international_stream™ << "Die Variable " << var << " ist undefiniert."; std::cout << international_stream™;
Intern hat international_stream
jetzt einen Speicher. Der erkennt, dass "Die Variable " zu dem oben angegeben Tripel gehören. Jetzt muss das Ding nur noch den Unterschied zwischen der Variable und dem Text erkennen. Das kann man über Typangaben lösen... Falls nicht, bräuchte man Manipulatoren:
international_stream™ << text1 << "Die Variable" << var1 << var << text2 << " ist undefiniert.";
oder man gibt ein paar Pattern:
international_stream™ << text_var_text << "Die Variable " << var1 << " ist undefiniert.";
Und dann haut der Stream das alles um, wenn er um die Ausgabe an cout gebeten wird. Blöd ist aber dennoch die Fragmentierung. Vll. gibt es auf irgend einer Sprache nicht links und rechts nen Text? Schlimmer: Vll. gibt es in der Zielsprache drei Fragmente. Letztlich ist man mit den Streams nicht so dynamisch.
Aber die Typsicherheit lässt sich doch sicher auch mit Format-Strings lösen, richtig?
-
Ach verflucht! Hast Recht.
Bei Formatstring macht man es einfach:
sprintf(Message, "Person %s nicht erwünscht!", Name); sprintf(Message, "Person %s is a fucking terrorist!", Name);
Bei Streams müsste man einen Vermittler bauen, der einen gestreamten Text erkennt, weiß, was davon dynamisch ist, und es entsprechend verdreht, wenn die Sprache geändert wird. Äußerst aufwendig. Es sei denn, man hängt halt wieder einen String rein, der nochmal analysiert und umgeschmissen wird, aber dann ist das ja keine wirkliche Stream-Lösung.
Genau auch deswegen die Frage. Denn die einfachste Lösung wäre ja ein sprintf für std::string. Aber dank audacia habe ich jetzt auch eine Lösung.
Message = str_printf("Person %s nicht erwünscht!", Name); Message = str_printf("Person %s is a fucking terrorist!", Name);
-
audacia schrieb:
Wenn du auf meiner Seite noch ein wenig weitergelesen hättest, wäre dir vielleicht aufgefallen, daß Typsicherheit sehr wohl erreichbar ist
Typsicherheit ist mit Ellipsen grundsätzlich niemals erreichbar! Alles andere ist Selbstbetrug.
Die Ursache liegt darin, daß bei Ellipsen eine variable Anzahl an Argumenten übergeben werden kann, und man durch den Compiler bzw. Linker keinerlei Chance hat, dies jemals sicher zu prüfen. Die ganzen C Format Funktionen können vom Compiler nur dann auf Übereinstimmung geprüft werden, wenn die Formatstrings als Konstanten im Aufruf vorliegen. Ist das nicht der Fall wird selbst diese Einfachprüfung ausgehebelt. Irgend welche Templatespielereien ändern an diesem grundsätzlichen Problem rein gar nichts. Wenn man die Prüfung gar zur Laufzeit verschiebt, hat man das Problem, daß man schon undefined behavior hat, wenn die Zahl der Argumente nicht mit der Anzahl an Formatstringeinträgen übereinstimmt, und somit die Prüfung bereits sinnlos geworden ist.
Was den Themenkomplex Übersetzungen von Software betrifft. Es funktioniert nur mit Einschränkungen einfach die Texte zu übersetzen, die Satzstellung und die Regeln für die Typographie sind in den Sprachen unterschiedlich. Am besten ist in so einem Fall ein polymorphes Verhalten der Ausgabefunktion, so daß man die Ausgabe auch wirklich an alle Erfordernisse der jeweiligen Sprache anpassen kann.
-
~john schrieb:
audacia schrieb:
Wenn du auf meiner Seite noch ein wenig weitergelesen hättest, wäre dir vielleicht aufgefallen, daß Typsicherheit sehr wohl erreichbar ist
Typsicherheit ist mit Ellipsen grundsätzlich niemals erreichbar! Alles andere ist Selbstbetrug.
Deswegen verwendet audacia ja auch Templates. Wenn du seinen den Artikel gelesen hättest, wüsstest du das
-
Warum kann man eigentlich nicht einfach
#include <cstdio>
einbinden und dann einfach mit sprintf() 'höchstpersönlich' arbeiten?
Was spricht denn da dagegen, dass man einfach eine schon längst
vorhandene Standard-Funktion (wie z.B. sprintf()) aufruft ?
Genau dazu ist ja so eine Funktion eigentlich da, damit man sie nicht
ständig neu erfinden muss, wenn man sie mal benötigt !!
Oder seh ich da was falsch ?
-
ExperteOhneWerte schrieb:
Warum kann man eigentlich nicht einfach
#include <cstdio>
einbinden und dann einfach mit sprintf() 'höchstpersönlich' arbeiten?
Was spricht denn da dagegen, dass man einfach eine schon längst
vorhandene Standard-Funktion (wie z.B. sprintf()) aufruft ?
Genau dazu ist ja so eine Funktion eigentlich da, damit man sie nicht
ständig neu erfinden muss, wenn man sie mal benötigt !!
Oder seh ich da was falsch ?Ich weiß auch nicht was dagegen spricht, aber vielleicht sind wir ja nur dumm.
std::string a("test lol"); printf("%s", a.c_str());
Ein temporärer String wird so oder so mit den Streamklassen auch entstehen. Weshalb ich die Ganzen Antworten nicht nachvollziehen will.
-
@ExperteOhneWerte:
Zeig mal wie du sprintf() verwenden willst, um das Ergebnis in einen std::string zu bekommen (was die ursprüngliche Frage des OP war).
Dann zeig ich dir, was an der Lösung schlecht ist.----
audacia hat ja bereits eine ausreichend einfache und für viele akzeptabel sichere Version gepostet (str_printf).
-
@HighLigerBiMBam:
Er willsprintf
(man beachte das S) mitstd::string
verwenden, nicht einenstd::string
mitprintf
ausgeben.
D.h. er möchte das Ergebnis in einemstd::string
haben.
-
hustbaer schrieb:
@HighLigerBiMBam:
Er willsprintf
(man beachte das S) mitstd::string
verwenden, nicht einenstd::string
mitprintf
ausgeben.
D.h. er möchte das Ergebnis in einemstd::string
haben.Ok da passe ich (es ist Freitag bin zu müde) und finde es sinnlos printf ist viel einfacher :p
-
Was heisst
printf
ist viel einfacher?
Wie willst du mit dem resultierenden String mitprintf
irgendwas machen, ausser ihn auf stdout auszugeben?Weisst du, es gibt nämlich Fälle wo man das braucht.
Und wenn man das braucht, dann ist "
printf
ist viel einfacher" ist eine ziemlich sinnlose Aussage. :p
-
hustbaer schrieb:
Was heisst
printf
ist viel einfacher?
Wie willst du mit dem resultierenden String mitprintf
irgendwas machen, ausser ihn auf stdout auszugeben?Weisst du, es gibt nämlich Fälle wo man das braucht.
Und wenn man das braucht, dann ist "
printf
ist viel einfacher" ist eine ziemlich sinnlose Aussage. :pHehe da magst du recht haben
-
Klar kann man nicht beides haben – Typsicherheit zur Kompilierzeit und Formatflags. Man kann aber sehr wohl Typsicherheit zur Laufzeit und Formatflags haben. Aber eben nicht mit der Ellipse.
Und wenn man mit Variadic Templates was bastelt, kommt das
boost::format
schon sehr nahe, auch wenn dort die etwas konventionellere Operatorüberladung angewendet wird.
-
Ich verstehe bis heute nicht warum es in C++ nicht eine Ausgabe mit Formatstring wie in C gibt, selbst PHP hat sowas.
Die C++ Lösung ist bestimmt manchmal sinnvoll, aber wie vieles in C++ extremst häßlich. Muss man ja zum Glück nicht nutzen...
-
Nexus schrieb:
Klar kann man nicht beides haben – Typsicherheit zur Kompilierzeit und Formatflags. Man kann aber sehr wohl Typsicherheit zur Laufzeit und Formatflags haben. Aber eben nicht mit der Ellipse.
Du hast ja meinen Artikel immer noch nicht gelesen
Natürlich ist es richtig; man kann Ellipsen nicht typsicher machen. Aber man kann Code, der "elliptische Funktionen" wie printf(), scanf() etc. benutzt, durchaus typsicher machen, und zwar ohne Änderungen am Code. Das ist auch im Wesentlichen der Sinn meines Unterfangens: bestehenden Code ohne Änderungen typsicher zu machen. Wenn man eine maximal flexible Lösung sucht, ist man mit boost.format oder String::Format() (C++Builder) besser bedient. (Das steht übrigens auch in meinem Artikel.)
-
fingerindenhals schrieb:
Ich verstehe bis heute nicht warum es in C++ nicht eine Ausgabe mit Formatstring wie in C gibt, selbst PHP hat sowas.
Selbstverständlich gibt es das in C++: sprintf()
[und überhaupt: die komplette C-Standardbibliothek muss ja in jeder
standardkonformen C++ Implementierung auch vorhanden und aufrufbar sein!]Das hier geschilderte Problem kommt ja auch nur dadurch zustande, weil einige
C++ Programmierer aus gänzlich irrationalen Gründen diese Funktionen nicht
verwenden wollen, weil sie von C kommen.Typ-Unsicherheit, Puffer-Überläufe usw. sind ja nicht eine negative Eigenschaft
dieser C-Funktionen, sondern doch wohl in erster Linie eine negative Eigenschaft
jener Programmierer, welche die Funktionen falsch verwenden, oder z.B. bei
sprintf() die zusätzlichen Parameter (z.B. wegen Tippfehler) vergessen
oder in einer falschen Reihenfolge angeben.).Beispiel 1:
char buffer[5]; sprintf(buffer, "%d", 101365);
Man kann doch in diesem Fall nicht sprintf() die Schuld dafür geben, dass
der Programmierer eine Zahl mit 6 Ziffern in ein Array für max. 5 Zeichen
hineinschreiben möchte ... (Aber genau auf diesee Weise wird gerne gegen
die Verwendung von Funktionen aus der C-Standardbibliothek - und gegen Pointer
ganz allgemein - argumentiert !!)
Beispiel 2:
int a = 1, b = -2; sprintf(buffer, "%d %d", a);
Nur noch wirklich UR-ALTE Compiler sind nicht dazu in der Lage, hier
zu bemerken, dass der Programmierer mehr Formatangaben als Parameter an
sprintf übergibt.
Aber auch in so einem Fall, wo der Compiler das 'schluckt'
und übersetzt, kann man wohl schwerlich die 'böse' C-Funktion sprintf()
für den logischen Fehler des Programmierers verantworlich machen.Und so ließe sich die Liste beliebig fortsetzen, ausnahmslos alle
scheinbar 'triftigen' Gründe gegen die (gelegentliche) Verwendung
der C-Funktionen aus <cstdio>, <cstring>, <cstdlib> in einem
C++ Programm enttarnen sich bei näherer Betrachtung eigentlich immer
als logische Fehler des Programmierers, aber doch bestimmt nicht
als Unzulänglichkeit z.B. von sprintf (das ja ebensogut in jedem
C++ Standard-Konformen Programm verwendet werden darf und idR. auch
verwendet werden sollte, bevor man sich selber irgend ein
quadratische Rad neu erfindet (so wie hier schon im ganzen Thread),
nur weil z.B. std::string so eine Funktion zur Zeit noch nicht anbietet,
und man nichts anderes gelernt hat, als mit std::string zu arbeiten ...)
-
In C++ ist man aber geneigt, möglichst viele Fehler schon beim Compilieren zu finden. Mit deiner Argumentation könnte man auch gegen Typsicherheit, Zugriffsmodofizierern bei Klassen, const correctness usw. argumentieren, oder kurz: jedes Programm ohne Syntaxfehler möge kompilieren, was kann der Compiler für logische Fehler des Programmierers?
Was ist z.B., wenn der Formatstring aus einer Lokalisierungsdatei kommt und sich irgendeiner den Spaß macht, da die falschen Formatflags einzutragen. Wie fängt man sowas mit sprintf ab, ohne vorher aufwendig den Formatstring zu analysieren? Dann könnte man das nämlich auch gleich selbst parsen. Es macht auch niemand, außer er wird genötigt, weil jemand darüber einen buffer overflow ausnutzte (gab es alles schon). Warum std::string? Die üblichen Gründe. Was ist, wenn besagter analysierter lokalisierter Formatstring in Sprache A 100 Zeichen braucht und in Sprache B 500? Wie viel Platz soll man reservieren? Wieder ein hübscher Fall für einen Buffer-Overflow.
Mit boost::format oder anderen vorgeschlagenen Lösungen hat man diese Probleme alle nicht.Ich hoffe du bist nicht derselbe volkommen ahnungslose C++-Basher wie in den anderen Threads. Man wird es daran erkennen, ob du in deiner Antwort wieder genau die selben Argumente wie eben bringst.
-
Kasperle3 schrieb:
Typ-Unsicherheit, Puffer-Überläufe usw. sind ja nicht eine negative Eigenschaft
dieser C-FunktionenDoch, sind sie. In anderen Sprachen und mit anderen Funktionen kann so etwas gar nicht passieren.
Kasperle3 schrieb:
Man kann doch in diesem Fall nicht sprintf() die Schuld dafür geben, dass
der Programmierer eine Zahl mit 6 Ziffern in ein Array für max. 5 Zeichen
hineinschreiben möchte ... (Aber genau auf diesee Weise wird gerne gegen
die Verwendung von Funktionen aus der C-Standardbibliothek - und gegen Pointer
ganz allgemein - argumentiert !!)
Hmm, ich halte Typsicherheit eigentlich für eine wertvolle Errungenschaft. Du nicht?
-
audacia schrieb:
Das ist auch im Wesentlichen der Sinn meines Unterfangens: bestehenden Code ohne Änderungen typsicher zu machen.
Ja, ich finde deine Lösung für diesen Fall ja auch gut
Sorry falls ich mich unklar ausdrückte. Ich meinte nur, dass die Lösung mit Operatorüberladung und die mit Variadic Templates relativ ähnlich im Bezug auf Typsicherheit seien. Aber es gibt natürlich andere Gründe, die für das eine oder andere sprechen.
Kasperle3 schrieb:
Man kann doch in diesem Fall nicht sprintf() die Schuld dafür geben, dass
der Programmierer eine Zahl mit 6 Ziffern in ein Array für max. 5 Zeichen
hineinschreiben möchte ...Nein,
sprintf()
kann nichts dafür. Es gibt halt in C keine bessere Technik mit ähnlichem Komfort als VarArgs. Aber wie schon angetönt ist es von enormem Vorteil, wenn man fehlervermeidende Techniken zur Verfügung hat (zur Kompilier- oder Laufzeit). Und in dieser Hinsicht gibt es in C++ eben massiv bessere Möglichkeiten alssprintf()
. Ansonsten siehe ipsec.Kasperle3 schrieb:
Und so ließe sich die Liste beliebig fortsetzen, ausnahmslos alle
scheinbar 'triftigen' Gründe gegen [unsichere Funktionen] enttarnen sich bei näherer Betrachtung eigentlich immer
als logische Fehler des Programmierers, aber doch bestimmt nicht
als Unzulänglichkeit z.B. von [unsicheren Funktionen]Interessante Argumentation. Ich nehme an, du brauchst auch nie
assert
, da man damit Logikfehler abfängt, die ja nur eine Unzulänglichkeit des Programmierers sind.
-
Ich hoffe du bist nicht derselbe volkommen ahnungslose C++-Basher wie in den anderen Threads.
Ich vermute schon dass er es ist. Besonders die manuelle Formatierung (Zeilenumbrüche) seines Posts deutet darauf hin.