Unicode läuft schneller als Ascii ?



  • @Artchi : Bah, ich kenne mich in der Richtung wohl wirklich wenig aus ;P
    Dieses Multi-byte Character Set, was Visual Studious zB als compile-Option bietet, entspricht dann dieser UTF-8 Kodierung ?

    Hatte ich behauptet, dass std::string Unicode ist ? Also ich dachte std::string ist lediglich Ascii.

    Um es nochmal für mich zusammen zu fassen : Wenn ich wstring verwende, unterstütze ich Unicode, benutze aber nicht die unperformante UTF-8 Kodierung ? Sondern habe immer eine festgelegte Grösse von 2 bytes pro zeichen ?

    @ Falsches Forum :t Du meintest wohl std::string braucht MEHR speicher als std::wstring ?



  • std::string -> für Codepages, also ASCII, Latin-1 usw. Immer nur 1 Byte.
    Siehe auch http://de.wikipedia.org/wiki/Codepage und http://de.wikipedia.org/wiki/Codepage_1252

    std::wstring -> immer nur 2 oder 4 Byte (je nach Compiler, aber NT und MSC++ wollen 2 Byte). Kann somit für UCS-2 (2 Byte) bzw. UCS4 (4 Byte) genutzt werden. Meines Wissens nutzt Mac OS X intern UCS-4.
    Siehe auch http://de.wikipedia.org/wiki/Universal_Character_Set

    UTF-8 wird von keiner Klasse im C++-Standard unterstützt. Es gibt sie einfach nicht. Selbst in C++0x ist da meines Wissens nichts geplant. Man muß (was auch Sinnvoller ist) UTF-8 aus einer Datenquelle (z.B. Datei) in UCS-2 bzw. UCS-4 konvertieren und dann einfach den wstring bearbeiten. Und beim raus schreiben (z.B. in eine UTF-8 Datei) das UCS-x in UTF-8 konvertieren. Das geht mit codecvt der C++-Streams.

    D.h. man darf UTF-8 nur für den Datenaustausch zwischen Systemen betrachten! Im Speicher arbeitet man immer mit UCS-x Strings. Wäre auch sinnlos im Programmcode für jeden Codetyp einen eigenen String-Typ zu haben. Da müsste man ja hunderte String-Klassen bereit stellen. Und in einem Webbrowser müssten mehrere String-Klassen alle HTML-Codierungen bedenken. Nein, die HTML-Seite wird gelesen, im Header steht die Kodierung, und wird beim Interpretieren in UCS-x für wstring konvertiert und der Web-Renderer interessiert sich auch nur für UCS-x.

    Andere Systeme (wie Linux) arbeiten intern mit UTF-8, aber das ist ja deren Entscheidung. Wenn die eine UCS-2-Datei lesen, konvertieren die intern alles in UTF-8. gehüpft wie gesprungen. 😉

    Siehe auch http://www.kharchi.eu/cpp_strings_i18n.html

    Somit kann man nicht sagen, das wstring mehr Speicher verbraucht als string. Weil die Leistung absolut unterschiedlich ist. Ich kann ja nicht sagen string ist besser, wenn es nicht die Leistung von wstring abdeckt. In einem UCS-x String (wie wstring) kann ich halt lateinische und arabische Zeichen haben. In std::string muß ich mich für eine Codepage entscheiden. Kommt also auf die Anforderung an. Wenn ich weiß "es gibt definitiv nur deutsche Zeichen", kann ich mit std::string besser leben.



  • Artchi schrieb:

    Andere Systeme (wie Linux) arbeiten intern mit UTF-8, aber das ist ja deren Entscheidung.

    Nur der Vollständigkeit halber: Linux arbeitet intern an den meisten Stellen mit Byte-Folgen und interpretiert dabei nichts. Deswegen kann man z.B. auf einem Linux-Dateisystem ohne weiteres eine Datei mit utf8-kodiertem Dateinamen und im selben Ordner eine andere Datei mit latin1-kodiertem Dateinamen anlegen. Die User-Tools wie die shell werden wahrscheinlich einen der beiden Dateinamen dann nicht richtig anzeigen, aber dem Linux-Kernel selber ist das egal, für den sind das nur uninterpretierte Folgen von Bytes. Das führt gelegentlich zu Problemen mit linux-fremden Dateisystemen wie NTFS, die ein bestimmtes Encoding vorschreiben.

    Windows benutzt meines Wissen nach intern schon seit Vista nur noch UTF-16 und nicht mehr UCS-2. UTF-16 ist ein Multiwort-Encoding ist mit Wortbreite von 16 Bit, kann dafür aber wenigstens alle Unicode-Codepoints darstellen.

    Nur UCS-2 zu unterstützen ist nicht so praktisch, find ich. Ich hab auch schon LaTeX-Dateien gehabt die Zeichen außerhalb der BMP enthielten (d.h. in UTF-16 nicht mehr mit 16 Bit darstellbar sind), was mit \usepackage[utf8]{inputenc} kein Problem ist.



  • Artchi schrieb:

    Das Problem bei UTF-8 ist das die Byte-Länge pro Zeichen dynamisch ist. Also muß doch praktisch bei jedem Buchstaben gerechnet werden, was es nun für ein Wert ist.

    Bei fester Byte-Größe (bei NT und wstring ist es immer 2x 1 Byte) muß nichts gerechnet werden.

    Das stimmt so auch nicht ganz. Unicode bietet ja auch "Combining characters" an. Das heißt, dass man selbst bei UCS4 schauen muss, ob man jetzt ein Zeichen hat.



  • Christoph schrieb:

    Windows benutzt meines Wissen nach intern schon seit Vista nur noch UTF-16 und nicht mehr UCS-2. UTF-16 ist ein Multiwort-Encoding ist mit Wortbreite von 16 Bit, kann dafür aber wenigstens alle Unicode-Codepoints darstellen.

    Soweit ich weiß, war das sogar schon ab Windows 2000 so.



  • Um ehrlich zu sein : Ich verstehe jetzt fast nurnoch Bahnhof ;P So viele verschiedenen Kodierungen ;O
    Es gibt also verschiedene Kodierungen für Unicode, was zB vom OS abhängt, richtig ?

    Wenn ich jetzt zB unter Visual C++ 2010 Multibyte Character-Sets einstelle, benutze ich eine bestimmte Kodierung für Unicode, oder ? UTF-8 falls ich das richtig rausgelesen habe.

    Und am Ende nochmal meine Frage ;P : Ich kann also generell statt std::string oder char einfach wchar und std::wstring verwenden ? Das scheint ja sogar schneller zu laufen, in allen Arten von Anwendungen.
    Mich hatte das nur verwundert, da ich das in noch keinem C++ Lehrbuch oder auch nicht in effective c++ als tipp gesehen habe. Es klingt aber sehr plausibel und wird wohl auch tatsächlich besser sein.
    Also std::wstring/wchar > std::string/char, right ?



  • typedef std::basic_string<TCHAR> tstring

    (oder halt mit ifdef auf wstring oder tstring mappen)

    Und fertig, nun einfach immer brav tstring verwenden und du hast keine Probleme sondern kannst es global mit einer Einstellung wechseln.

    (Sobald die Applikation Lokalisiert wird, und auch in asiatische Sprachen, kommst du so oder so nicht um wstring drum herum. Daher machte ich alles immer pauschal wstring und fertig, ob gebraucht oder nicht)



  • David W schrieb:

    typedef std::basic_string<TCHAR> tstring

    (oder halt mit ifdef auf wstring oder tstring mappen)

    Und fertig, nun einfach immer brav tstring verwenden und du hast keine Probleme sondern kannst es global mit einer Einstellung wechseln.

    Kann ich mit dem Dateinamen in einem tstring dann auch einen ifstream öffnen? Oder gibt's da einen wifstream?



  • David W schrieb:

    typedef std::basic_string<TCHAR> tstring
    [...]
    Und fertig, nun einfach immer brav tstring verwenden und du hast keine Probleme sondern kannst es global mit einer Einstellung wechseln.

    Dann liefert aber tstring::length() nur die Länge in Wörtern (TCHAR), nicht die Anzahl der Codepoints. Denn Windows benutzt bei Unicode ja UTF-16, also ein multi-word encoding, wo ein Codepoint 2 wchar_t's lang sein kann. Das hat zum Beispiel insofern Auswirkungen, dass man den String nicht zerschneiden oder kürzen kann ohne (recht aufwändig) das Encoding zu berücksichtigen. Man könnte ja sonst aus Versehen ein Multiwort-Codepoint in der Mitte zerschneiden.

    Der Vergleich auf Gleichheit ist genauso problematisch, aber aus anderen Gründen: Unicode definiert, wann zwei Strings äquivalent sein sollen (http://en.wikipedia.org/wiki/Unicode_equivalence). Diese Äquivalenz-Begriffe in Unicode sind *nicht* Byte-für-Byte-Äquivalenz. Zum Beispiel kann ein A mit Kringel dargestellt werden als

    1. "A" gefolgt von "Kringel über dem letzten Buchstaben"
    2. "Å"

    Falls TCHAR=wchar_t, dann machen die Vergleichsoperatoren von std::basic_string also nicht unbedingt das richtige, wenn man die Strings vorher nicht normalisiert.



  • Dann halt

    #ifdef _UNICODE
    typedef std::wstring tstring
    #else
    typedef std::string tstring
    #endif

    Is doch gretzky...

    Wenn man mit Strings arbeitet und die Zerpflücken will/muss, muss man sowieso die korrekte Position suchen wo man abschneidet oder einfügt, da ist es egal ob string oder wstring



  • volkard schrieb:

    David W schrieb:

    typedef std::basic_string<TCHAR> tstring

    (oder halt mit ifdef auf wstring oder tstring mappen)

    Und fertig, nun einfach immer brav tstring verwenden und du hast keine Probleme sondern kannst es global mit einer Einstellung wechseln.

    Kann ich mit dem Dateinamen in einem tstring dann auch einen ifstream öffnen? Oder gibt's da einen wifstream?

    Suchst du sowas hier?

    typedef std::basic_stringstream<TCHAR> tstringstream;

    (Das findet man alles hier im Forum ebenso)



  • David W schrieb:

    Dann halt

    #ifdef _UNICODE
    typedef std::wstring tstring
    #else
    typedef std::string tstring
    #endif

    Is doch gretzky...

    Ja, das ist wirklich egal. Das kommt nämlich genau aufs selbe heraus, denn std::wstring kann auch nicht mit multi-word encodings umgehen. Die combining characters hat man in jedem Fall, auf Gleichheit testen kann man also auch mit std::wstring nicht so, wie das mit Unicode gedacht ist.

    David W schrieb:

    Wenn man mit Strings arbeitet und die Zerpflücken will/muss, muss man sowieso die korrekte Position suchen wo man abschneidet oder einfügt, da ist es egal ob string oder wstring

    Vielleicht möchte ein simples Konsolen-Programm sagen "10 Zeichen des Strings möchte ich ausgeben und falls mehr Zeichen im String sind, wird der Rest durch ... abgekürzt."

    Das ist mit Unicode schon eine erstaunlich komplizierte Aufgabe.



  • David W schrieb:

    Wenn man mit Strings arbeitet und die Zerpflücken will/muss, muss man sowieso die korrekte Position suchen wo man abschneidet oder einfügt, da ist es egal ob string oder wstring

    Die WinAPI bietet diverse Funktionen zum Arbeiten mit Unicode-Strings, welche einem die tricky parts abnehmen. Man sollte die daher auch verwenden, wenn's geht.



  • David W schrieb:

    volkard schrieb:

    David W schrieb:

    typedef std::basic_string<TCHAR> tstring

    (oder halt mit ifdef auf wstring oder tstring mappen)

    Und fertig, nun einfach immer brav tstring verwenden und du hast keine Probleme sondern kannst es global mit einer Einstellung wechseln.

    Kann ich mit dem Dateinamen in einem tstring dann auch einen ifstream öffnen? Oder gibt's da einen wifstream?

    Suchst du sowas hier?
    typedef std::basic_stringstream<TCHAR> tstringstream;
    (Das findet man alles hier im Forum ebenso)

    Nein, ich suche ifstream. Und der Dateiname soll Unicode sein.
    http://www.cplusplus.com/reference/iostream/ifstream/ifstream/



  • volkard schrieb:

    David W schrieb:

    volkard schrieb:

    David W schrieb:

    typedef std::basic_string<TCHAR> tstring

    (oder halt mit ifdef auf wstring oder tstring mappen)

    Und fertig, nun einfach immer brav tstring verwenden und du hast keine Probleme sondern kannst es global mit einer Einstellung wechseln.

    Kann ich mit dem Dateinamen in einem tstring dann auch einen ifstream öffnen? Oder gibt's da einen wifstream?

    Suchst du sowas hier?
    typedef std::basic_stringstream<TCHAR> tstringstream;
    (Das findet man alles hier im Forum ebenso)

    Nein, ich suche ifstream. Und der Dateiname soll Unicode sein.
    http://www.cplusplus.com/reference/iostream/ifstream/ifstream/

    Ich stelle mir jetzt folgendes Szenario vor:

    Gegeben ist ein Ordner, der zwei Dateien enthält.
    Name der ersten Datei ist ein Zeichen: "A mit Kringel drüber".
    Name der zweiten Datei ist zwei Zeichen: "A" + "Kringel über dem letzten Zeichen".

    Nach Unicode sind diese Namen äquivalent, ein unicode-konformes Dateisystem dürfte also (soweit ich das auffasse) diese Situation überhaupt nicht erst zulassen, weil dann zwei unterschiedliche Dateien mit äquivalentem Dateinamen im selben Ordner liegen.

    Mac-Dateisysteme lassen das nicht zu, weil die ihre Dateinamen normalisieren. NTFS speichert seine Dateinamen zumindest in einem einheitlichen Encoding, aber ob Windows die Dateinamen normalisiert, weiß ich nicht. Linux lässt dieses Szenario zu, weil Linux Dateinamen als Bytefolgen ansieht.

    Eine Unicode-API zum Dateiöffnen müsste diese beiden Dateinamen aber als äquivalent ansehen. Falls also nur eine dieser beiden Dateien existiert, müsste man sie unter zwei unterschiedlichen Namen öffnen können.

    Ich finde zumindest nicht offensichtlich, wie man das korrekt implementiert, ohne dass es zu Problemen führt. Vielleicht ist der Mac-Ansatz gar nicht so schlecht: Dateinamen immer normalisieren. Dann kann es die oben beschriebene Situation nicht geben, weil man die zweite Datei nicht im selben Ordner anlegen kann. Man kann die eine existierende Datei unter beiden Dateinamen öffnen, weil die Namen normalisiert äquivalent sind.

    So eine Methode verändert aber eben die Bytes eines Dateinamen und verbietet pauschal Dateinamen, die nicht unicode-kodiert sind. Ich könnte mir Situationen vorstellen, bei denen das zu Bugs führt.


Anmelden zum Antworten