C++ string und Umlaute
-
Hallo,
kann ich in einem std::string eigentlich Umlaute speichern? Ich habe einen String "bäh" und wenn ich mir das "b" als char hole mit char c = s[1], dann hat c den Wert -28.
Damit std::string Umlaute unterstützt, müsste string::operator[] doch unsigned char und nicht char liefern, oder?
-
Also erstmal holst Du Dir das 'ä', weil in C/C++ Felder und alles was dem nahe kommt normalerweise 0-basiert sind.
Und dann speicherst du den Wert in einem signed char, für den der Wert von 'ä' zu groß ist, daher Überlauf ins Negative (Binär hat sich nichts geändert, es geht da nur um die Interpretation der Werte).
-
Das ist mir alles schon klar.
Ich frage mich nur, ob dann ein std::string überhaupt geeignet ist für Umlaute. Wäre er dafür gebaut worden, hätte operator[] doch als Rückgabewert einen unsigned char, oder?
-
Ich habe einen String "bäh" und wenn ich mir das "b" als char hole mit char c = s[1], dann hat c den Wert -28.
Dir ist schon klar, dass die Indizierung bei 0 anfängt? Und das die -28 für das 'ä' stehen?
-
lol. Natürlich ist mir das klar! Oh man...
Es geht hier um das char und unsigned char! Und nicht um den blöden Index!
-
Es ist nicht definiert, ob char nun signed oder unsigned ist, soweit ich informiert bin. Aber die Bibliotheken sind für den vorliegenden Fall ausgelegt, also brauchst Du dir keine Sorgen machen, dass dein 'ä' die Bibliothek vor Probleme wirft, so du denn das richtige locale eingestellt hast. Und wenn du unbedingt eine positive Zahl für den 'ä' sehen willst, konvertierst du das char vorher in ein unsigned char, dann bekommst du auch die richtige dezimale Kodierungszahl auf dem Bildschirm ausgegeben.
-
Karli31 schrieb:
Ich frage mich nur, ob dann ein std::string überhaupt geeignet ist für Umlaute. Wäre er dafür gebaut worden, hätte operator[] doch als Rückgabewert einen unsigned char, oder?
Warum soll er denn einen unsigned char und keinen char haben?
228 unsigned char ist dasselbe wie -28 signed char. Ich sehe erstmal nicht den Vorteil von unsigned char gegenüber signed char.string hat alle Nachteile, die char hat, nämlich dass es nur 256 verschiedene Zeichen gibt und das nicht für alle Zeichen reicht. Ein unsigned char behebt dieses Problem nicht, ein short int hilft da schon weiter (wstring).
Ich kann mir vorstellen, dass in deiner extended ASCII-Tabelle steht "ä = 132". Und vielleicht hast du dir gedacht ein unsigned char kann den Wert 132 annehmen und signed char nicht und deswegen ist string für Umlaute nicht geeignet und wäre mit unsigned chars besser geeignet (ich hoffe meine Glaskugl funktioniert). Praktisch macht es einfach keinen Unterschied, aber wenn du gerne möchtest kannst du sowas hier machen:
#include <string> #define string std::basic_string<unsigned char>
Und schon hat der []-Operator ein unsigned char als Rückgabewert.
Btw signed ist standard für chars und ints, deswegen sieht man auch häufig unsigned aber praktisch nie signed.
-
ein short int hilft da schon weiter (wstring).
Ja, nur das
std::wstring wchar_t
als Zeichentyp benutzt... undshort
damit nicht wirklich irgendwas zu tun hat.Btw signed ist standard für chars und ints, deswegen sieht man auch häufig unsigned aber praktisch nie signed.
Vom Standard ist nicht festgelegt, ob ein
char
ohne explizite Angabe vorzeichenbehaftet ist oder nicht - sprich, ob einsigned char
oderunsigned char
einemchar
gleicht. Das ist von der Implementierung festgelegt.Edit: Verdammt! Ich wiederhole schon wieder was Decimad sagt, ohne es zu ahnen.
:xmas2:
-
Sone schrieb:
ein short int hilft da schon weiter (wstring).
Ja, nur das
std::wstring wchar_t
als Zeichentyp benutzt... undshort
damit nicht wirklich irgendwas zu tun hat.1. Geht es ihm darum dass man einen 16bit Integer zum Speichern von Zeichen haben möchte, short ist gewöhnlich 16bit groß.
2. Sind short und wchar_t unter Windows der selbe Datentyp.
-
Sone schrieb:
ein short int hilft da schon weiter (wstring).
Ja, nur das
std::wstring wchar_t
als Zeichentyp benutzt... undshort
damit nicht wirklich irgendwas zu tun hat.1. Geht es ihm darum dass man einen 16bit Integer zum Speichern von Zeichen haben möchte, short ist gewöhnlich 16bit groß.
Und was hat jetzt
std::wstring
damit zu tun?Ethon schrieb:
2. Sind short und wchar_t unter Windows der selbe Datentyp.
Soso. Dann frage ich mich, wieso auf meinem Windows-system
std::is_same
das Gegenteil behauptet.
Vielleicht haben sie dieselbe Größe, das ist etwas völlig anderes. Außerdem schreibt ein wide-stream etwas völlig anderes rein, wenn du stattwchar_t(500) short(500)
insertest.
-
Karli31 schrieb:
kann ich in einem std::string eigentlich Umlaute speichern?
Wenn das "execution character set" Umlaute enthält, ja. Was das "execution character set" ist, hängt davon ab, auf welcher Platform du bist und welchen Compiler du verwendest. Beispielsweise sagt die Dokumentation des Microsoft Compilers, dass sowohl "source character set" als auch "execution character set" ASCII sind. Und in ASCII gibt es keine Umlaute. Wenn Du jetzt deinen Quellcode in einem Editor bearbeitest, der statt ASCII eben ISO-8859-15 verwendet, kannst du einen Umlaut im Quelltext abspeichern und der Microsoft Compiler wird das wohl einfach "fressen". Dann kommt es darauf an, was die Console damit anstellt, wenn du ein solches Zeichen ausgibst. Aber eigentlich bewegst du dich damit außerhalb dessen, was Microsoft selbst spezifiziert.
Karli31 schrieb:
Ich habe einen String "bäh" und wenn ich mir das "b" als char hole mit char c = s[1], dann hat c den Wert -28.
Du meinst das 'ä', richtig? -28 ist dann zu erwarten, wenn du deine Quelltextdatei in der ISO-8859-1 oder ISO-8859-15 Kodierung speicherst, der Compiler das einfach frisst, char bei ihm vorzeichenbehaftet ist und Dein Rechner das 2er Komplement beherrscht. Beachte, dass all diese Dinge nicht vorgeschrieben sondern Platform-abhängig sind.
Karli31 schrieb:
Damit std::string Umlaute unterstützt, müsste string::operator[] doch unsigned
char und nicht char liefern, oder?Nö. "unsigned char" für Zeichen ist recht unüblich. Es sagt auch keiner, dass all die gültigen Werte des execution character sets positiv sein müssen (wenn ich mich da nicht vertue). Aber da das execution characterset eh bei dir ASCII ist -- ich rate einfach mal, dass du unter Windows mit VS ("Visual Soundso") arbeitest -- spielt das ja keine Rolle, da die ASCII-Codes nur 7-bittig sind.
Ich weiß nicht, ob Microsoft überhaupt ganz offiziell Umlaute über char auf der Konsole bietet. Da char ja 8 Bit breit sind, kann man natürlich mehr als nur ASCII nach std::cout rausschicken. Wie das dann angezeigt wird, hängt dann auch davon ab, welche "code page" du in der Konsole aktiv hast.
Ist das nicht herrlich kompliziert alles?
-
Ethon schrieb:
short ist gewöhnlich 16bit groß.
Definiere "gewöhnlich". Es gibt einige Betriebssysteme, diverse Compiler, 32bit und 64bit Architekturen. Auf einigen der Kombinationen wird short auch mal größer als 16bit sein. Und die (oder deren User) werden sich evtl. beschweren, wenn du sie als "ungewöhnlich" bezeichnest
2. Sind short und wchar_t unter Windows der selbe Datentyp.
Unter Windows - 32bit oder 64bit? Welcher Compiler? MSVC? GCC? Intel? Hast du alles ausprobiert, dass du das so sicher sagen kannst?
Was ich damit sagen will: Geht nicht von irgendwelchen "üblicherweise", "gewöhnlich" oder "Bei mir ist das so also überall woanders auch"-Aussagen aus. Verlasst euch auf das, was definiert ist, und arbeitet damit.
std::string ist nunmal char-basiert, und char hat garantiert einen Wertebereich von 0-127, nicht mehr und nicht weniger. Das bedeutet: std::string unterstützt ASCII, also keine Umlaute. Wer Umlaute möchte, sollte std::wstring benutzen, der basiert auf wchar_t, nicht auf short, long, oder sonstwas.
Ich darf aktuell eine in 15 Jahren "historisch gewachsene" Codebase auf 64bit Systeme portieren. Die >5000 Warnungen, weil size_t und unsigned int plötzlich nicht mehr das Selbe sind, gehören noch zum kleineren Übel. Hartcodierte Größen ("hey,
sizeof(void*)
ist doch IMMER 4") und Bitpatterns (sizeof(foo) | 1<<31
) kommen da schon übler.Schreibt portablen Code, dann gibts in 2-10 Jahren bei der Umstellung auf
<some new compiler here>
unter<insert new fancy OS here>
keine bösen Überraschungen.
-
Ethon schrieb:
1. Geht es ihm darum dass man einen 16bit Integer zum Speichern von Zeichen haben möchte, short ist gewöhnlich 16bit groß.
Ich denke nicht, dass du das einfach so behaupten kannst, dass "man das so möchte".
Ethon schrieb:
2. Sind short und wchar_t unter Windows der selbe Datentyp.
Das hast du nicht so gemeint, denn es widerspricht dem C++ Standard (§3.9.1/5)
Type wchar_t is a distinct type [...]
Was du meintest, ist, dass der Typ denselben Wertebereich hat wie einer der Ganzzahltypen.
-
Vielleicht haben sie dieselbe Größe, das ist etwas völlig anderes. Außerdem schreibt ein wide-stream etwas völlig anderes rein, wenn du statt wchar_t(500) short(500) insertest.
Die Frage ist eher, was deine Streamimplementation an der stelle meint darin zu erkennen ....
Übirigens, mit Compilereinstellungen kannst du bestimmen, das wchar_t als eigener Datentyp behandelt wird, unter windows bleibt er damit 2 Byte gros und verhält sich wie ein short, aber jegliche Kompatiblitaet wird dann vom compiler abgestritten
d.h. umwandlungen von short zu wchar_t muss man dann expliziet casten.
So isses zumindest beim VS@Karli31
kann ich in einem std::string eigentlich Umlaute speichern?
Du kannst damit alles Speichern, was 1 Byte Zeichenbreite hat. NULL als Sonderzeichen wird nur relevant, wenn du C-kompatibel arbeitest.
Du musst dir aber im klaren sein, das std::string nur ein Transportcontainer ist. Was aufm Bildschirm aufploppt, ist meist Interpretation der darstellungs- und Erzeugungs-schicht. Wenn Darstellung und erzeugung mit der gleichen Codierung arbeiten, passt meist alles.
Aber, liest du ein file ein was utf8 kodiert ist, und gibst es an eine Funktion, die beispielsweisse ISO 8859-1 codierung annimmt, werden alle Sonderzeichen etwas komisch aussehen ^^
Ciao ...
-
krümelkacker schrieb:
Ethon schrieb:
2. Sind short und wchar_t unter Windows der selbe Datentyp.
Das hast du nicht so gemeint, denn es widerspricht dem C++ Standard (§3.9.1/5)
Type wchar_t is a distinct type [...]
Was du meintest, ist, dass der Typ denselben Wertebereich hat wie einer der Ganzzahltypen.
Nein, ich dachte wirklich dass ein wchar_t auch ein Alias auf einen anderen builtin-type sein dürfte. Danke für die Aufkärung.
Definiere "gewöhnlich". Es gibt einige Betriebssysteme, diverse Compiler, 32bit und 64bit Architekturen. Auf einigen der Kombinationen wird short auch mal größer als 16bit sein. Und die (oder deren User) werden sich evtl. beschweren, wenn du sie als "ungewöhnlich" bezeichnest
Naja, die Aussage war mehr oder weniger, dass er eine 16bit Ganzzahl als unterliegenden Typ möchte, da jede Kodierung, die auf 16bit Zahlen operiert, in einer einzigen 16bit Zahl alle deutschen Umlaute speichern kann.
Da basic_string ein ziemlich dummer Container ist, der keine Ahnung hat was er da speichert, hätte es in der Umsetzung auch kein abweichendes Verhalten, selbst wenn short 128bit groß wäre (außer natürlich Speicherverschwendung).Vielleicht haben sie dieselbe Größe, das ist etwas völlig anderes. Außerdem schreibt ein wide-stream etwas völlig anderes rein, wenn du statt wchar_t(500) short(500) insertest.
Dass die überladenen Operatoren der Streams je nach Situation Unsinn machen ist ein allgemeines Problem wie ich finde. Aber eher bei char, wchar_t nimmt niemand für gewöhnliche Integer.
-
Entweder verwendet man die String-Klasse von C++ oder char-arrays von C.
Beides durcheinander ist kuddelmuddel und macht wenig Sinn.
-
RHBaum schrieb:
Vielleicht haben sie dieselbe Größe, das ist etwas völlig anderes. Außerdem schreibt ein wide-stream etwas völlig anderes rein, wenn du statt wchar_t(500) short(500) insertest.
Die Frage ist eher, was deine Streamimplementation an der stelle meint darin zu erkennen ....
"was deine Streamimplementation an der stelle meint darin zu erkennen"? Was soll das denn heißen?
-
RHBaum schrieb:
Vielleicht haben sie dieselbe Größe, das ist etwas völlig anderes. Außerdem schreibt ein wide-stream etwas völlig anderes rein, wenn du statt wchar_t(500) short(500) insertest.
Die Frage ist eher, was deine Streamimplementation an der stelle meint darin zu erkennen ....
wchar_t c = 123; std::wcout << c;
gibt ein Zeichen aus, mit short wäre es die Zahl 123.