VisialStudio: MultiByte vs Unicode



  • xor schrieb:

    Die 9x-Windows-Reihe unterstützte nur ANSI (Multibyte) in der WinAPI, dort gab es es kein Unicode (außer man hatte den Unicode-Layer nachinstalliert).

    ANSI encoding (korrekt eigentlich Windows 1252) ist doch kein Multibyteencoding. Das passt doch alles schön in ein Byte (256 Zeichen).



  • rüdiger schrieb:

    xor schrieb:

    Die 9x-Windows-Reihe unterstützte nur ANSI (Multibyte) in der WinAPI, dort gab es es kein Unicode (außer man hatte den Unicode-Layer nachinstalliert).

    ANSI encoding (korrekt eigentlich Windows 1252) ist doch kein Multibyteencoding. Das passt doch alles schön in ein Byte (256 Zeichen).

    Ja da hast du natürlich recht, wobei meines Wissens "ANSI" (bei API-Funktionen) für so ziemlich alles stehen kann, was aus einzelnen Bytes besteht. Die ANSI-Funktionen arbeiten dann (bitte korregiert mich, wenn ich irre 😃 ) unter einem chinesischen Windows mit einem chinesischen Multi-Byte (Double-Byte) String, während sie bei uns mit Windows-1252 (also Single-Byte) nutzen.

    Für mich bedeutet daher ANSI unter Windows nur "irgend ein lokal-kodierter Byte-String". Aber das ist so nicht korrekt formuliert ... stimmt 😉

    Für das Speichern von Daten hat sich UTF8 für mich bewährt, eben weil man es unter Linux stillschweigend für System-Aufrufe nutzen kann. Unter Windows ist das allerdings eine ungute Herumkonvertiererei. Der einzige Verteil ist, das UTF-8 in ein reguläres char-Array passt und so wunderbar system-unabhängig in Dateien geschrieben werden kann. Wenn man unter Windows Unicode benutzt verwendet man immer UTF-16, da der wchar_t 16 bit breit ist, während wchar_t unter vielen Unices 32 bit breit ist und UTF-32 darstellt.

    Wer unter Windows

    fwrite(L"Hello World", sizeof(wchar_t), 11, f);
    

    schreibt, bekommt unter Linux mit

    wchar_t buffer[20] = { 0 };
    fread(buffer, sizeof(wchar_t), 11, f);
    

    Probleme 😃

    cu
    XOR



  • mir stellt sich auch noch ein Frage

    Warum kann man nicht mehr folgendes schreiben:

    std::wstring dirINI;
    dirINI = SallyAPI::System::SystemHelper::GetModulePath();
    dirINI.append("option.ini");

    Also die letzte Zeile... hiefür muss man ja jetzt

    dirINI.append(L"option.ini");

    oder

    dirINI.append(_T("option.ini"));

    schreiben... oder liegt das an Project/Compiler Einstellungen?



  • Was ist genau dier Frage?
    Warum der wstring keine automatische Konvertierung von "const char*" hat?

    Das frage ich mich auch schon immer...



  • Also die technische Erklärung ist einfach: std::string ist ein std::basic_string<char> und std::wstring ist ein std::basic_string<wchar_t>. Und damit kann ein std::string nur mit char umgehen während ein std::wstring nur mit wchar_t umgehen kann 😉

    Ich mache daher meist folgendes

    #if defined(UNICODE) || defined(_UNICODE)
    #  define tstring wstring
    #else
    #  define tstring string
    #endif
    

    Im Projekt benutze ich dann immer den "tstring" und das _T - Makro.

    PS: Man kann sich aber auch eine eigene String-Klasse schreiben, wo die Methoden entsprechend überladen sind und dann MultiByteToWideChar / WideCharToMultiByte einsetzen 😃



  • mh, ne eigene Klasse klingt jetzt aber auch nicht gerade reizvoll
    Also muss ich überall die Makros verwenden?

    Was für eins ist da jetzt besser? L oder _T?


  • Administrator

    Der_Knob schrieb:

    Was für eins ist da jetzt besser? L oder _T?

    L ist kein Makro, sondern ein Sprachteil von Standard C++. L sagt dem Kompiler, dass das Stringliteral ein Widestring darstellen soll. Also in Code:

    char const* c = "hello"; // ist ein char[6]
    wchar_t const* w = L"hello"; // ist ein wchar_t[6]
    

    _T ist ein Kompilerabhängiges Makro und nicht Teil von Standard C++. Das Makro _T ist unter MSVC ca. wie folgt definiert:

    #if defined(UNICODE)
    # define _T(x) L ## x
    #else
    # define _T(X) x
    #endif
    
    // Wenn UNICODE gesetzt ist, expandiert folgender Ausdruck:
    _T("hello")
    // zu
    L"hello"
    // Falls UNICODE nicht gesetzt ist, dann wird daraus:
    "hello"
    

    Wenn du sowieso kein Multibyte verwenden willst und nur Unicode, wozu ich eigentlich auch raten würde, dann verwende immer gleich L , wchar_t und std::wstring . Die Makros kannst du dir sparen.

    Jochen Kalmbach schrieb:

    Das frage ich mich auch schon immer...

    Ich hoffe, dass dies nicht dein Ernst ist? Ansonsten:
    http://www.gotw.ca/gotw/019.htm

    Grüssli



  • Aber warum nicht auf Multibyte stellen?
    Man verwendet normal ASCII Strings und wo man Unicode braucht, nimmt man es halt.



  • Hä? Wie soll denn das gehen? Das ist ja dann ein furchbares durcheinander was kaum durchgängig funktionieren wird...



  • Wenn man auf Unicode stellt, kann man doch gar keine ASCII-Stringliterale mehr definieren?!
    In einigen Anwendungen braucht man aber sowohl ASCII/ANSI (whatever lol) und Unicode. Dann stellt man halt auf Multibyte und wo man char* braucht, definiert man char* = "", und wo man wchar_t* braucht, definiert man halt wchar_t* = L""...
    Nicht?


  • Administrator

    Hi schrieb:

    Wenn man auf Unicode stellt, kann man doch gar keine ASCII-Stringliterale mehr definieren?!

    Wie kommst du auf den Unsinn? Grundsätzlich wird nur das Makro UNICODE gesetzt. Wodurch die WinAPI Funktionen zur W-Funktion expandieren. Also zum Beispiel aus MessageBox wird dann MessageBoxW . Es hindert dich aber niemand daran direkt MessageBoxA aufzurufen.

    Hi schrieb:

    In einigen Anwendungen braucht man aber sowohl ASCII/ANSI (whatever lol) und Unicode. Dann stellt man halt auf Multibyte und wo man char* braucht, definiert man char* = "", und wo man wchar_t* braucht, definiert man halt wchar_t* = L""...

    Wenn du auf Unicode stellst, kannst du dies genau gleich verwenden. Daran ändert die Einstellung nichts.

    Grüssli



  • xor schrieb:

    Für das Speichern von Daten hat sich UTF8 für mich bewährt, eben weil man es unter Linux stillschweigend für System-Aufrufe nutzen kann. Unter Windows ist das allerdings eine ungute Herumkonvertiererei. Der einzige Verteil ist, das UTF-8 in ein reguläres char-Array passt und so wunderbar system-unabhängig in Dateien geschrieben werden kann. Wenn man unter Windows Unicode benutzt verwendet man immer UTF-16, da der wchar_t 16 bit breit ist, während wchar_t unter vielen Unices 32 bit breit ist und UTF-32 darstellt.

    UTF-8 und UTF-16 sind ja sogar VariableByte :).

    IMHO sind UTF-8 und UTF-32 die einzig sinnvollen Unicodevarianten. Der Rest ist nur für Spezialfälle und Legacysysteme. UTF-8 ist gut, wenn man den Text möglichst klein haben will oder eben für Legacysysteme :). UTF-32 ist gut, wenn man sehr viel zeichenweise machen will.



  • UTF-16 ist gut, wenn man WinAPI Funktionen direkt ansprechen will... das geht nun mal mit UTF-8 nicht da Windows dies nicht als Encoding seiner *A-Funkionen nicht unterstützt.
    Fazit: Verwende möglichst immer die *W-Funktionen, wenn Du alle Zeichensätze darstellen willst... und damit verwende auch "wchar_t" bzw. "UTF-16".

    UTF-32 wird in der Praxis nie eingesetzt...


  • Administrator

    rüdiger schrieb:

    UTF-8 ist gut, wenn man den Text möglichst klein haben will oder eben für Legacysysteme :).

    Nicht zum Beispiel im asiatischen Raum. Wenn ich mich recht erinnere brauchen gerade chinesische Zeichen in UTF-8 meistens 3 Bytes, während sie in UTF-16 nur 2 Bytes benötigten. Daher wird UTF-16 noch oft im asiatischen Raum eingesetzt.

    rüdiger schrieb:

    UTF-32 ist gut, wenn man sehr viel zeichenweise machen will.

    Kannst du auch bei UTF-32 vergessen. Gewisse Zeichen setzen sich aus mehreren UTF-32 Werten zusammen. Man braucht genauso Indextabellen wie in UTF-8 und UTF-16.

    Ein Vorteil von UTF-8 ist, dass man keine Unterscheidung zwischen LE und BE hat.

    Grüssli



  • Dravere schrieb:

    rüdiger schrieb:

    UTF-8 ist gut, wenn man den Text möglichst klein haben will oder eben für Legacysysteme :).

    Nicht zum Beispiel im asiatischen Raum. Wenn ich mich recht erinnere brauchen gerade chinesische Zeichen in UTF-8 meistens 3 Bytes, während sie in UTF-16 nur 2 Bytes benötigten. Daher wird UTF-16 noch oft im asiatischen Raum eingesetzt.

    Aber nur wenn es sich um reinen Text handelt. Das kommt ja mittlerweile eher selten vor. Wenn Steuerzeichen (sind ja idr aus dem ASCII Satz) enthalten sind, dann ist UTF8 auch hier besser. Wenn du mir nicht glauben willst, dann kannst du es ja einfach ausprobieren. Nimm dir ein paar zh/ja-Wikipedia-Seiten und kodier die einmal als UTF8 und einmal als UTF16. UTF8 gewinnt da deutlich.

    Für den japanischen UTF-8: UTF-8 vs. UTF-16: 100453 vs. 171166 Bytes. UTF-8 gewinnt mit 41.3% Vorsprung.

    Dravere schrieb:

    rüdiger schrieb:

    UTF-32 ist gut, wenn man sehr viel zeichenweise machen will.

    Kannst du auch bei UTF-32 vergessen. Gewisse Zeichen setzen sich aus mehreren UTF-32 Werten zusammen. Man braucht genauso Indextabellen wie in UTF-8 und UTF-16.

    Nein. UTF-32 nutzt 32Bit für alle Zeichen. Es gibt keine Indextabelle. (UCS-4 braucht 24Bit für Zeichen).



  • Jochen Kalmbach schrieb:

    UTF-16 ist gut, wenn man WinAPI Funktionen direkt ansprechen will... das geht nun mal mit UTF-8 nicht da Windows dies nicht als Encoding seiner *A-Funkionen nicht unterstützt.
    Fazit: Verwende möglichst immer die *W-Funktionen, wenn Du alle Zeichensätze darstellen willst... und damit verwende auch "wchar_t" bzw. "UTF-16".

    Wie ich sagte: UTF-16 für Legacysysteme.

    Jochen Kalmbach schrieb:

    UTF-32 wird in der Praxis nie eingesetzt...

    Klar, wenn man Unicode mit einfachem Zeichenzugriff haben will. Bei UTF-8/16 muss man ja immer umständlich schauen wo welches Zeichen ist.


  • Administrator

    rüdiger schrieb:

    Aber nur wenn es sich um reinen Text handelt. Das kommt ja mittlerweile eher selten vor.

    Wie bitte? Selten? Also ich kenne da einige Anwendungen, wo reiner Text gespeichert wird. Wenn ich nur an all die Datenbanken denke, welche reinen Text abspeichern.

    rüdiger schrieb:

    Nein. UTF-32 nutzt 32Bit für alle Zeichen. Es gibt keine Indextabelle. (UCS-4 braucht 24Bit für Zeichen).

    Bringt nur nichts, wenn man kombinierte Zeichen verwendet. Du kannst zum Beispiel ein A schreiben mit einem zusätzlichen diakritischem Zeichen.

    Wir haben sogar einen Unicode Artikel, falls es dich interessiert 😉

    Grüssli



  • rüdiger schrieb:

    Dravere schrieb:

    rüdiger schrieb:

    UTF-32 ist gut, wenn man sehr viel zeichenweise machen will.

    Kannst du auch bei UTF-32 vergessen. Gewisse Zeichen setzen sich aus mehreren UTF-32 Werten zusammen. Man braucht genauso Indextabellen wie in UTF-8 und UTF-16.

    Nein. UTF-32 nutzt 32Bit für alle Zeichen. Es gibt keine Indextabelle. (UCS-4 braucht 24Bit für Zeichen).

    Nein. Du solltest Dich mal näher mit Unicode beschäftigen... oder meinen Artikel hier im Forum lesen...

    Es gibt einen riesen großen Unterschied zwischen einem *Codepoint* und einem Zeichen (Glyph).
    Du redest hier nur von Codepoints... das spielt aber in der *richtigen* Welt keine Rolle... da kommt es nur darauf an, dass Du die Zeichen ricjhtig interpretierst und z.B. bei einer Suche nicht zusammenhängende Codepoints (z.B. via Combining Characters) separat betrachtest...



  • Stimmt an die Combiningcharacters hab ich gar nicht gedacht. Dann ist UTF-32 also wirklich nicht sehr sinnvoll.

    Dravere schrieb:

    rüdiger schrieb:

    Aber nur wenn es sich um reinen Text handelt. Das kommt ja mittlerweile eher selten vor.

    Wie bitte? Selten? Also ich kenne da einige Anwendungen, wo reiner Text gespeichert wird. Wenn ich nur an all die Datenbanken denke, welche reinen Text abspeichern.

    Also wenn man eine Anwendung ausschließlich für den chinesischen Markt schreibt und nur reinen chinesischen Text behandelt, dann ist UTF-16 vielleicht doch eine Überlegung wert. Das zähle ich mal als Spezialfall.


  • Administrator

    rüdiger schrieb:

    Also wenn man eine Anwendung ausschließlich für den chinesischen Markt schreibt und nur reinen chinesischen Text behandelt, dann ist UTF-16 vielleicht doch eine Überlegung wert. Das zähle ich mal als Spezialfall.

    Dann bezeichnest du bereits die chinesische Wirtschaft als Spezialfall. Und es gibt noch einige zusätzliche Länder in der Gegend, welche Software einsetzen, welche ausschliesslich für ihr Gebiet programmiert ist.

    Zudem vergisst du wohl, dass Windows auf UTF-16 aufbaut. Wieso ständig immer zwischen Kodierungen hin und her konvertieren, wenn das Programm sowieso auf Windows läuft? Daher kenne ich einige, welche zum Beispiel die Sprachdateien in UTF-16LE halten.

    Aber gut, du kannst natürlich einfach eine riesige Gruppe machen und diese "Spezialfall" nennen 🤡

    Grüssli


Anmelden zum Antworten