Eigenen Typ "String" in c++ deffinieren - wie?
-
Bitsy schrieb:
Dazu muß man aber auch sicherstellen, daß es einfach nicht gelingt, nachträglich ein 0-Zeichen in dem String unterzubringen.
WARUM?
Für eine solche Operation wäre eine von String abgeleitete Klasse sinnvoll.
WARUM?
Ich sehe die Gefahr nicht. In einen std::string kann ich auch 0-Zeichen reinstopfen, wie ich mag und habe ich damit keinen Ärger.
-
hustbaer schrieb:
Klassische Pascal String verwenden ein fixed-size Array (typischerweise 256 Byte gross). Im ersten Byte steht die aktuelle Länge, danach kommt der Text. Nullterminiert sind sie dafür nicht.
Das erste Byte als Größenangabe, der Rest als Zeichenfolge, keine Nullterminierung. Soweit klar.
Aber fixed-fized Array klingt nach tierischer Speicherplatzverschwendung. Daran mag ich nicht glauben. Zumal es nicht notwendig wäre, weil Pascal (im Gegensatz zu Basic) schon zu Zeiten des 64-ers eine Freispeicherverwaltung hatte. Kann es sein, daß die 640k vom DOS, sagen wir mal 500k Vokabelprogramm frei, nur 1000 Vokabelsätze gepaßt haben oder nur 500 Records mit Name/Vorname/Straße/Ort.
-
volkard schrieb:
hustbaer schrieb:
Klassische Pascal String verwenden ein fixed-size Array (typischerweise 256 Byte gross). Im ersten Byte steht die aktuelle Länge, danach kommt der Text. Nullterminiert sind sie dafür nicht.
Das erste Byte als Größenangabe, der Rest als Zeichenfolge, keine Nullterminierung. Soweit klar.
Aber fixed-fized Array klingt nach tierischer Speicherplatzverschwendung. Daran mag ich nicht glauben. Zumal es nicht notwendig wäre, weil Pascal (im Gegensatz zu Basic) schon zu Zeiten des 64-ers eine Freispeicherverwaltung hatte.War aber so, gerade weil man dem Programmierer beim Arbeiten mit Strings manuelle Speicherverwaltung à la C ersparen wollte.
Modernere Implementationen von Pascal (Delphi) verwenden ähnlich wie BSTR zusätzliche vier Bytes vor den eigentlichen Stringdaten, wo die Länge gespeichert wird; der String wird vollständig auf dem Heap alloziert (mit Referenzzählung und COW-Semantik), und so sind String-Variablen nur sizeof(void*) groß. Der Nachteil ist, daß
Length(theString)öfter mal einen Cache-Miss verursacht - aber i.d.R. kann der Compiler redundante Aufrufe (z.B. in einer Schleifenbedingung) ohnehin wegoptimieren.Ein schöner Aspekt dieser Implementation ist, daß der Compiler Stringliteralen gleich die Länge und einen angpaßten Referenzzähler voranstellen kann, so daß bei
const cSomeLiteral = 'some literal'; var S: String; SL: Integer; begin S := cSomeLiteral;keine Kopie angelegt, sondern nur der Referenzzähler erhöht werden muß, und
SL := Length (cSomeLiteral);sich auf eine Zeigerdereferenzierung beschränken kann.
Zwecks Kompatibilität mit dem Windows-API und C++Builder sind die Strings natürlich dennoch zusätzlich nullterminiert.
-
audacia schrieb:
War aber so, gerade weil man dem Programmierer beim Arbeiten mit Strings manuelle Speicherverwaltung à la C ersparen wollte.
die operatoren für strings waren doch eingebaut, oder? also kein new, strcpy und strcat.
hast du irgend eine quelle für diene these?
-
volkard schrieb:
die operatoren für strings waren doch eingebaut, oder? also kein new, strcpy und strcat.
In Wirths Pascal war, soweit ich mich erinnere, gar nichts dergleichen eingebaut; es gab nicht einmal einen Stringtypen (http://www.moorecad.com/standardpascal/pascalfaq.html#Q.%20How%20do%20I%20perform%20string%20operations%20in%20standa).
volkard schrieb:
hast du irgend eine quelle für diene these?
Nicht zur Hand, nein. Aber es liegt eigentlich nahe: für jeden String eine Heap-Allokation wurde als zu teuer angesehen, und so war ein stackbasierter String mit Komfort-Erweiterungen gegenüber
array[0..x] of charein guter Kompromiß.In der Implementation von Turbo Pascal war es darüber hinaus möglich, die Maximallänge des Strings explizit anzugeben:
var S: String[20]; // 21 Bytes großÜbrigens kannst du ja einfach Turbo Pascal herunterladen und nachschauen.
-
ok. bin überzeugt.
wieder was dazugelernt.
-
Falls es dich noch interessiert, hier ein uszug aus der Delphi-Doku zu "ShortString", der aus Kompatibilität zu TP auch heute noch zur Verfügung steht.
Delphi Hilfe schrieb:
Kurze String-Typen
Ein ShortString hat eine Länge von 0 bis 255 Zeichen. Obwohl sich seine Länge dynamisch ändern kann, beträgt die statische Speicherplatzzuweisung immer 256 Bytes. Im ersten Byte wird die Länge des Strings gespeichert, die restlichen 255 Byte stehen für die Zeichen zur Verfügung. Wenn S eine ShortString-Variable ist, gibt Ord(S[0]) die Länge von S zurück (dasselbe Ergebnis erzielen Sie mit Length(S)). Durch Zuweisung eines Wertes an S[0] können Sie (wie durch einen Aufruf von SetLength) die Länge von S ändern. ShortString wird nur aus Gründen der Abwärtskompatibilität mitgeführt.Delphi unterstützt kurze String-Typen (Untertypen von ShortString), deren maximale Länge zwischen 0 und 255 Zeichen liegen kann. Diese Typen werden mit einer Zahl in eckigen Klammern dargestellt, die auf das reservierte Wort string folgt. Zum Beispiel:
var MyString: string[100];Hier wird die Variable MyString mit einer maximalen Länge von 100 Zeichen erstellt. Die folgenden Deklarationen sind mit der obigen Zeile identisch:
type CString = string[100]; var MyString: CString;Bei Variablen, die auf diese Weise deklariert werden, wird dem Typ nur so viel Speicherplatz zugewiesen, wie für die angegeben Länge plus ein Byte erforderlich ist. Im obigen Beispiel belegt MyString 101 Byte. Für eine Variable des vordefinierten Typs ShortString wären dagegen 256 Byte erforderlich.
Bei einer Wertzuweisung an eine kurze String-Variable wird der String abgeschnitten, wenn die maximale Länge für den Typ überschritten wird.
Die Standardfunktionen High und Low bearbeiten Variablen und Typbezeichner für kurze Strings. High liefert die maximale Länge des kurzen String-Typs, während Low Null zurückgibt.
-
Don06 schrieb:
Falls es dich noch interessiert, hier ein uszug aus der Delphi-Doku zu "ShortString", der aus Kompatibilität zu TP auch heute noch zur Verfügung steht.
danke. das hat die sache noch hübsch abgerundet.
-
volkard schrieb:
Bitsy schrieb:
Dazu muß man aber auch sicherstellen, daß es einfach nicht gelingt, nachträglich ein 0-Zeichen in dem String unterzubringen.
WARUM?
Für eine solche Operation wäre eine von String abgeleitete Klasse sinnvoll.
WARUM?
Ich sehe die Gefahr nicht. In einen std::string kann ich auch 0-Zeichen reinstopfen, wie ich mag und habe ich damit keinen Ärger.
Ganz einfach 'axiomatisch'. Wenn du irgendwann aus irgendwelchen Gründen den eigentlichen cString mal wieder rausholst, kann der Zirkus losgehen.
Wie ich geschrieben hatte, eine abgeleitete Klasse bei der das 0 erlaubt ist, z.B. mit Namen stringbuffer, sagt mir da rein gefühlsmäßig mehr zu.Ich glaube, ich hatte damals sogar Gründe dafür, frag nicht, ist so lange her.
-
Dravere schrieb:
Ehm, hä? Ich verstehe immer noch nicht, was gegen die Klasse
std::stringspricht
Im Gegenteil, es erscheint mir die bessere Lösung zu sein.std::stringführt schliesslich intern die Grösse des Strings mit.Zur Lösung von Nexus:
Das geht nur, so lange das Array vorhanden ist. Sobald du ein Zeiger hast, geht diese Lösung nicht mehr.Grüssli
so kannst du verstehen, das erwähnen lieber std::string zu bevorzugen ist ein netter hinweis, doch jeder hat vl ein vorhaben, std::string erst mal zu verzichten und eigene string zu bauen, um mehr kenntnis zu erwerben. diese vl nur zum Testzwecke.
-
JnZn558 schrieb:
so kannst du verstehen, das erwähnen lieber std::string zu bevorzugen ist ein netter hinweis, doch jeder hat vl ein vorhaben, std::string erst mal zu verzichten und eigene string zu bauen, um mehr kenntnis zu erwerben. diese vl nur zum Testzwecke.
Hättest du den Thread gelesen, wüsstest du, dass es um etwas völlig anderes geht.
-
Bitsy schrieb:
...Wenn du irgendwann aus irgendwelchen Gründen den eigentlichen cString mal wieder rausholst, kann der Zirkus losgehen....
Zum einen gibt's keinen "eigentlichen cString da drin" - es ist vollkommen egal, wie std::string seine Daten intern organisiert.
Zum Anderen: Wieso sollte das mit einem "Pascalstring" anders sein, wenn man "den eigentlichen cString wieder rausholt" ?
Du erzählst hier von einer grundlegenden Schwäche von CStrings ... egal, ob Du sie aus irgendeinem Datentyp konvertierst und wenn, aus welchem.Gruß,
Simon2.
-
...aus einem selbstkonstruierten. Über den STL-string selbst habe ich gar kein Wort verloren.
-
Bitsy schrieb:
...aus einem selbstkonstruierten....
Auch wenn der CString aus einem von Dir selbst konstruierten Stringobjekt konstruiert wurde, hat er keine Möglichkeit, mehrere '\0'-en zu enthalten.
... oder er ist kein CString (oder exakter gesprochen: "NTCS" = "Null Terminated Character String").Die Quelle ist egal: JEDER CString hat diese Schwäche.
Gruß,
Simon2.
-
Was aber nicht allzu dramatisch sein sollte. Oder wie oft benutzt ihr
'\0'als Zeichen imstd::string?
-
Nexus schrieb:
Was aber nicht allzu dramatisch sein sollte. Oder wie oft benutzt ihr
'\0'als Zeichen imstd::string?Sehe ich ja auch so ... aber es ist als einziges (vermeintliches) Argument gegen std::string stehengeblieben und das ist auch noch falsch.

Gruß,
Simon2.
-
Ganz einfach 'axiomatisch'. Wenn du irgendwann aus irgendwelchen Gründen den eigentlichen cString mal wieder rausholst, kann der Zirkus losgehen.
Nein nicht wirklich. Da length() eine Laenge liefert und man mit 0-terminierten Strings z.B. mittels strncat, strncmp, strncpy ... arbeiten kann. Somit ist die 0-terminierung fuer cStrings nicht zwingend noetig. Diese Funktionen sind auch den normalen vorzuziehen, da sie bei richtiger Verwendung die Gefahr fuer Bufferoverflows, code injection etc vermindern. Leider sind sie aus Bequemlichkeit recht selten im Einsatz oder verbreitet.
-
knivil schrieb:
...
Hmmm, ich sehe nicht, wie die n-Varianten (die ich natürlich auch vorziehe - mal abgesehen von der a) oftmals falschen Anwendung und b) der Schwäche (IMHO) in der Definition) bei "doppelten \0-en" helfen soll. Z.B. zu strncpy(): "...If the length of the C string in source is less than num, only the content up to the terminating null-character is copied...."
Ich sehe das schon so, dass "CStrings" per definitionem auf Nullterminierung angewiesen sind...
Selbst da, wo man mittels "n-Funktionen" die Wahrscheinlichkeit von Bufferoverflows verringert, muss man die Nullterminierung sicherstellen, wenn man wieder "vernünftig" damit arbeiten will....Gruß,
Simon2.