Hallo, ich habe große Schwierigkeiten mit den verschiedenen Datentypen in C++. Im Internet findet man Beispiele sowohl in Unicode als auch in Multibyte. Wenn ich nun mitten in einem Programm stecke und zufällig einen lehrreichen Beispielcode im "anderen" Format finde, geht der Ärger los... Ich begegne auch immer wieder API-Funktionen, die zwar LPSTR zurückliefern, aber anscheinend die Zeichen in Byte-Form speichern, also kein Unicode. Das ist natürlich ungünstig, wenn man sich zu Beginn für Unicode entschieden hat. Kennt jemand eine gute Informationsquelle für Anfänger im Internet, wo kurz und knackig die verschiedenen Datentypen und auch die Umwandlungen erklärt werden? Quellen gibt es ja genug, aber ich habe so meine Probleme mit dem Verständnis...die folgende Erklärung habe ich Beispielsweise für die Funktion c_str() gefunden: "The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only granted to remain unchanged until the next call to a non-constant member function of the string object." Ok, also ein Null-Terminiertes Array mit dem Inhalt des String. Ich frage mich jedoch, warum die Werte in dem Array nicht verändert werden sollten und was es nun genau mit dieser garantierten Unversehrtheit der Werte bis zum nächsten ominösen Funktionsaufruf auf sich hat? Mit freundlichen Grüßen, Rocker
Rocker schrieb: > Ich begegne auch immer wieder API-Funktionen, die zwar LPSTR Übe an gescheitem C++-Code und nicht an dem, was Microsoft darunter versteht. Deren Typenkatastrophe ist schlimm. > "The returned array points to an internal location with the required > storage space for this sequence of characters plus its terminating > null-character, but the values in this array should not be modified in > the program and are only granted to remain unchanged until the next call > to a non-constant member function of the string object." > Ok, also ein Null-Terminiertes Array mit dem Inhalt des String. Genau, ein klassischer C-String. > Ich frage mich jedoch, warum die Werte in dem Array nicht verändert > werden sollten Sie gehören dir nicht, ganz banal. > und was es nun genau mit dieser garantierten > Unversehrtheit der Werte bis zum nächsten ominösen Funktionsaufruf auf > sich hat? Das heißt: Wenn du dir mit c_str() den C-String liefern lässt und z.B. in einer char*-Variablen festhälst:
1 | string EinCppString = ...; |
2 | char *s = EinCppString.c_str(); |
Dann ist der Inhalt des Arrays, auf das 's' nun zeigt (eben dein C-String) nur so lange korrekt (heißt hier: entspricht dem, was 'EinCppString' auch enthält), so lange nicht neuerlich auf 'EinCppString' herumgeackert wird. Du führst ja eine Redundanz ein: Einerseits weiß 'EinCppString' natürlich über seinen Inhalt Bescheid, der in irgendeiner Form verwaltet wird. Mittels c_str() forderst du nun aber eine möglicherweise gänzlich andere Darstellung des Inhaltes an, d.h. schlimmstenfalls kopiert 'EinCppString' seinen Inhalt, um ihn dir dann irgendwie anders aufbereitet zur Verfügung zu stellen. Wenn du nun an der Kopie herumfummelst, kriegt das Original das nicht mit. Wenn du am Original herumfummelst, kriegt die Kopie das nicht mit (denn sie müsste ja z.B. wieder neu aufbereitet werden usw.) -> Deshalb nur gültig, bis zum nächsten Fummeln an 'EinCppString'.
> ich habe große Schwierigkeiten mit den verschiedenen Datentypen in C++. > Im Internet findet man Beispiele sowohl in Unicode als auch in > Multibyte. Wenn ich nun mitten in einem Programm stecke und zufällig > einen lehrreichen Beispielcode im "anderen" Format finde, geht der Ärger > los... > Ich begegne auch immer wieder API-Funktionen, die zwar LPSTR > zurückliefern, aber anscheinend die Zeichen in Byte-Form speichern, also > kein Unicode. Das ist natürlich ungünstig, wenn man sich zu Beginn für > Unicode entschieden hat. Erst einmal ganz grundsätzlich: - Die Programmiersprachen C und C++ kennen eigentlich keine Strings, sondern nur eine Möglichkeit, Zeichenkonstanten anzugeben, die automatisch durch ein Zeichen mit dem Wert 0 (ASCII: NUL) abgeschlossen werden. Alles andere ist in Bibliotheken implementiert, z. B. die C-Standardbibliothek (Funktionen wie strcpy()) oder die C++-STL (z. B. die Klasse std::string). - Sogenannte C-Strings oder "nullterminierte Strings" sind entweder solche Zeichenkonstanten oder Variablen im gleichen Format bzw. Zeiger darauf. Beispiel:
1 | char* abc = "ABC"; |
Das definiert ein konstantes Character-Array von 4(!) Zeichen, nämlich A, B, C und einem 0-Byte, und einen Zeiger mit Namen abc darauf. - Der Bezeichner LPSTR stammt aus einer Microsoft-Bibliothek und ist kein Standard. - In C sind ursprünglich nur einfache Zeichen definiert, z. B. im ASCII-Standard. Der ASCII-Standard legt nur 7-Bit-Zeichen bis 127 fest, z. B., daß ein A als das Zeichen Nummer 65 codiert wird. Wenn man Umlaute oder Sonderzeichen braucht, die nicht Bestandteil des zugrundeliegenden Zeichensatzes wie ASCII sind, dann muß man sich überlegen, wie man diese codiert. Da gibt es verschiedene Ansätze: 1. Codepages (z. B. ISO-8859-1): Man behält 1 Byte pro Zeichen bei, aber sagt, welche Bedeutung die Zeichen über 127 haben sollen, z. B. als welche Zahl ich ein Ü codiere. Wenn irgendwo im Internet (E-Mails, Foren, ...) kaputte Umlaute auftauchen, dann ist der Grund meistens ein Problem mit Code pages. Codepages sollte man für neuere Projekte nicht mehr verwenden, es sei denn, man hat z. B. ein Embedded-System, dessen Display sowieso nur 8 Bits pro Zeichen erlaubt oder so. 2. Multi-Byte-Zeichensätze, immer noch mit Code pages. Das wurde z. B. für asiatische Sprachen benutzt, verwenden mehrere Bytes pro Zeichen und ist weitestgehend überholt. 3. Unicode: Dort hat man sich zusammengesetzt und sich überlegt, wie man die Zeichen praktisch sämtlicher Sprachen der Welt ohne Codepage-Chaos codieren kann. Herausgekommen ist eine Codierung, die in älteren Unicode-Versionen jedem Zeichen eine 16-Bit-Zahl und in neuen Unicode-Versionen eine 32-Bit-Zahl zuordnet. Dabei sind die unteren 127 Zeichen identisch mit dem ASCII-Zeichensatz. Da 16 oder 32 Bits sehr unhandlich sind (ein "char" hat je nach Plattform meist nur 8 Bit), hat man sich verschiedene Codierungen überlegt. Die gebräuchlichsten sind: UTF-8: Dabei wird ein Zeichen variabel mit 1 bis 3 Bytes (in neueren Unicode-Versionen max. 4) dargestellt. Weil UTF-8 eine echte Obermenge von ASCII ist, kann man es wie ASCII bearbeiten, solange keine Sonderzeichen vorkommen (zum ersten Experimentieren vielleicht in Ordnung, aber ein fertiges Programm, das man herausgibt, sollte damit rechnen!). UTF-16: Dabei wird ein Zeichen mit 2 Bytes (in neueren Unicode-Versionen 2 oder 4) dargestellt. UTF-32: Dort wird jedes Zeichen in 4 Bytes dargestellt. Bei Unicode muß man also wissen, mit welcher Unicode-Variante man es zu tun hat. Am gebräuchlichsten und meiner Meinung nach meistens am handlichsten ist UTF-8, auch UTF-16 sieht man öfters, z. B. bei Java. > Quellen gibt es ja genug, aber ich habe so meine Probleme mit dem > Verständnis...die folgende Erklärung habe ich Beispielsweise für die > Funktion c_str() gefunden: > > "The returned array points to an internal location with the required > storage space for this sequence of characters plus its terminating > null-character, but the values in this array should not be modified in > the program and are only granted to remain unchanged until the next call > to a non-constant member function of the string object." > > Ok, also ein Null-Terminiertes Array mit dem Inhalt des String. > Ich frage mich jedoch, warum die Werte in dem Array nicht verändert > werden sollten und was es nun genau mit dieser garantierten > Unversehrtheit der Werte bis zum nächsten ominösen Funktionsaufruf auf > sich hat? Das bedeutet folgendes: Wenn die Funktion c_str() (wahrscheinlich eher eine "Methode" einer Stringklasse wie std::string, oder?) aufgerufen wird, dann muß die Funktion einen Zeiger auf einen Speicherbereich liefern, in dem die Zeichen des Strings plus ein NUL-Zeichen stehen. Dazu muß sie unter Umständen den String in einen neuen, größeren Speicherbereich kopieren, um Platz für das NUL-Zeichen zu schaffen. Die Funktion kümmert sich selbst um die Verwaltung dieses Speicherbereichs. Darum darf der Aufrufer diesen Speicherbereich nur lesen, aber nicht freigeben (free()/delete) und nicht verändern, sonst ist das Verhalten undefiniert. Nehmen wir zum Beispiel an, die Funktion würde einen Zeiger auf eine interne Datenstruktur des Strings zurückliefern und der Aufrufer würde diesen Speicherbereich ändern - dann würde sich auch der String ändern! Es könnte auch zum Beispiel theoretisch sein, daß die Bibliothek als Optimierung einen Zeiger auf eine Konstante zurückliefert. Bei modernen Betriebssystemen mit Speicherschutz (wohl eher weniger bei Mikrocontrollern) könnte das dazu führen, daß das Betriebssystem das Programm beendet, anderenfalls wäre undefiniertes Verhalten die Folge. Darum ist diese Methode als "const" deklariert, damit man das nicht versehentlich tut. Und Du darfst den Rückgabewert dieser Funktion oder Methode nur so lange benutzen, bis die nächste Methode an diesem Stringobjekt aufgerufen wird, die nicht "const" ist. Wenn Du z. B. an den String etwas anfügst, dann ist der Rückgabewert des vorigen Aufrufs von c_str() ab diesem Zeitpunkt undefiniert und c_str() muß erneut aufgerufen werden, wenn der Wert das nächste mal gebraucht wird.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.