> 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:
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.