VisialStudio: MultiByte vs Unicode



  • Ich wollte mal ein paar Fragen zu MultiByte vs Unicode Einstellung bei VisualStudio Projekten stellen.

    Wie wichtig ist die Umstellung von MultiByte auf Unicode? Wird MultiByte irgendwann nicht mehr unterstützt werden?

    Was für Vorteile bringt mir die Umstellung?

    Was hat das für Performance Einflüsse hat die Umstellung?

    Danke schon mal!



  • Vereinfacht gesagt macht Multibyte ab Studio 2008 keinen Sinn mehr.
    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).
    Windows NT+ implementiert beide APIs, wobei intern mit Unicode gearbeitet wird und die ANSI APIs hin- und her-konvertieren mussten... das sollte auch bei Windows 7 weiter so sein.

    Nachdem aber mit dem Studio 2008 der Support für NT4 und Win9x eingestellt wurde und die EXEen von diesen System auch gar nicht mehr erkannt werden, macht es keinen Sinn mit Studio 2008 ein Multibyte Programm zu erzeugen. Es würde zwar auf den neueren Versionen von Windows laufen, aber ist performance-technisch gesehen eher ein Nachteil. Letztes Studio für alte Windows Versionen mit Nur-Multibyte ist also 2005.

    Wer aber mit TCHARs arbeitet, kann leicht zwischen Unicode und Multibyte umschalten 😉

    Ob die ANSI-Versionen der WinAPI irgend wann einmal nicht mehr unterstützt sind ist schwer zu sagen. So lange eine größere Anzahl an Programmen die eine oder andere API nutzt, kann MS es sich eigentlich nicht leisten die Kompatibilität zu brechen. Sogar in Windows Vista und 7 neu eingeführte APIs sind immer nocht doppelt implementiert (ANSI und Unicode) ...
    Bedenkt man aber, dass der Support für 16-bit Programme nun auch eingestellt ist, kann es durchaus passieren, dass das übernächste Windows keine ANSI - APIs mehr hat 😮 (da würden einige DLLs kleiner werden 😃 )

    Ein Vorteil von Unicode ist natürlich die korrekte Speicherung und Darstellung von allen weltweit genutzten Codes. Mir ist da eine dumme Backup-Software bekannt, die beim Sichern und Wiederherstellen einiger russischer bzw. japanischer Dateien kaputte Dateinamen generierte ... worauf dann Links nicht mehr funktionierten usw. Sowas ist für mich ein klassicher ANSI-Fehler (da haben meine Programme auch schon darunter gelitten 🙄 )
    Typischer Fehler ist: Deutsches Windows speichert ANSI-Dateinamen oder URL in eine Datei/Datenbank
    Japanisches Windows liest ANSI-String und versucht die Ressource zu öffnen -> FileNotFound/404 ...

    lg XOR 🙂



  • Danke für die ausführliche Antwort!

    Das hat dann mal alle meine Fragen beantwortet 👍
    Da ich mit VS 2008 entwickle werde ich dann auf Unicode umstellen



  • Wie sieht das denn jetzt aus, wenn ich portierbare Programme für Windows und Linux schreiben will? Verwende ich jetzt auch einfach immer Unicode?



  • daersc schrieb:

    Wie sieht das denn jetzt aus, wenn ich portierbare Programme für Windows und Linux schreiben will? Verwende ich jetzt auch einfach immer Unicode?

    Wie willst du die WinAPI für Linux benutzen? 🤡



  • Ich dachte eher an ein übergreifendes Toolkit wie wxWidgets...



  • 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


Anmelden zum Antworten