std::string / std::wstring



  • Hallo alle zusammen,

    Ich verwende Visual Studio 2012 und habe in meinem Projekt den Zeichensatz auf Multibyte gesetzt, was für Auswirkungen hat das nun genau auf mein Projekt?

    Desweiteren frage ich mich wann ich std::string und std::wstring verwenden sollte. Wenn ich hier im Forum unterwegs bin und mir einige Codes anschaue, dann sehe ich meistens nur std::string, es scheint so als ob std::wstring eher wenig gebraucht wird, aber eigentlich ist std::wstring doch am wichtigsten, oder?

    Angenommen ich programmiere unter Windows und lese mit einer Funktion den Computernamen aus, auf einem deutschen PC sollte es da keine Probleme geben, doch was genau passiert wenn das Programm auf einem russischen PC ausgeführt wird? std::string kann keine kyrillischen Zeichen enthalten, demnach müsste ich std::wstring verwenden, oder? Wenn ich nun doch std::string verwendet habe, ist dieser String dann einfach ungültig und „kaputt“, oder kann man nach einer Konvertierung zu std::wstring tatsächlich noch an den Namen kommen?

    Viele Grüße
    Markus



  • std__markus schrieb:

    Ich verwende Visual Studio 2012 und habe in meinem Projekt den Zeichensatz auf Multibyte gesetzt, was für Auswirkungen hat das nun genau auf mein Projekt?

    Du hast nur noch ASCII. Keine Umlaute, ß usw. (nicht portabel siehe unten)

    std__markus schrieb:

    Desweiteren frage ich mich wann ich std::string und std::wstring verwenden sollte. Wenn ich hier im Forum unterwegs bin und mir einige Codes anschaue, dann sehe ich meistens nur std::string, es scheint so als ob std::wstring eher wenig gebraucht wird, aber eigentlich ist std::wstring doch am wichtigsten, oder?

    Wenn du nur englische Buchstaben brauchst und dir ein paar Nanosekunden performance wichtig sind, dann nimm string, ansonsten wstring.
    Unter Linux ist wstring wegen UTF32 statt UTF16 deutlich langsamer und außerdem haben sich Linuxer dran gewöhnt, dass Unicode nicht funktioniert, unter Windoof sieht das anders aus.

    std__markus schrieb:

    Wenn ich nun doch std::string verwendet habe, ist dieser String dann einfach ungültig und „kaputt“, oder kann man nach einer Konvertierung zu std::wstring tatsächlich noch an den Namen kommen?

    Er ist kaputt. ASCII hat erweiterte Zeichensätze, das heißt du kannst Glück haben dass alle Elemente auf zum Beispiel deutschen erweiterten Zeichensatz eingestellt sind und dann kriegst du auch mit string Umlaute hin, aber wenn das Programm mit anderer Zeichentabelle ausgeführt wird kommt Schwachsinn raus. Du bist also auf eine einzige Sprache beschränkt.

    Weiterhin macht es für die Code-Beispiele im Forum keinen Unterschied ob du string oder wstring nimmst.



  • Danke schonmal für die schnelle Antworte, eine Frage habe ich allerdings noch: Wenn ich nun in Visual Studio 2012 den Zeichensatz auf Unicode gestellt habe und dennoch std::string in meinem Projekt verwende, wie wird das ganze dann behandelt? Wird std::string dann automaisch als std::wstring behandelt?



  • http://www.utf8everywhere.org/

    Nimm immer std::string und UTF-8

    Wenn der String falsch angezeigt wird, dann hast du was falsch eingestellt.



  • std__markus schrieb:

    Wenn ich nun in Visual Studio 2012 den Zeichensatz auf Unicode gestellt habe und dennoch std::string in meinem Projekt verwende, wie wird das ganze dann behandelt? Wird std::string dann automaisch als std::wstring behandelt?

    Nö.
    std::string verwendet immer char . Es gibt Stellen wo automatisch konvertiert wird, z.B. kann man IIRC nen std::string auf std::wcout ausgeben.
    An den meisten Stellen musst du dann aber selbst konvertieren wenn du nen std::wstring aus nem std::string machen willst.



  • std__markus schrieb:

    Ich verwende Visual Studio 2012 und habe in meinem Projekt den Zeichensatz auf Multibyte gesetzt, was für Auswirkungen hat das nun genau auf mein Projekt?

    Das hat nur Auswirkungen auf die typedefs/defines der WinAPI, heißt CreateWindow wird mit Multibyte auf CreateWindowA defined, und mit Unicode auf CreateWindowW. Auf C++ hat diese Einstellung also erst mal keinen Effekt.

    std__markus schrieb:

    Desweiteren frage ich mich wann ich std::string und std::wstring verwenden sollte. Wenn ich hier im Forum unterwegs bin und mir einige Codes anschaue, dann sehe ich meistens nur std::string, es scheint so als ob std::wstring eher wenig gebraucht wird, aber eigentlich ist std::wstring doch am wichtigsten, oder?

    Nein, du willst so gut wie immer std::string mit UTF-8 benutzen. Dir muss nur bewusst sein, dass .length() und .size() die die Anzahl der Byte, nicht die Anzahl der Zeichen geben. (Und dass du mit operator [] und Iteratoren über Bytes iterierst, nicht Zeichen.) Leider hat C++ eine ziemlich, sagen wir mal, dünne Unicode Unterstützung. Solche Dinge wie Zeichen Zählen/Finden musst du selbst schreiben, und das ist nicht ganz trivial. (Es gibt allerdings auch Bibliotheken dafür.) Wobei das Tolle an UTF-8 natürlich ist, dass du erst mal einfach nur ASCII benutzen kannst, und wenn du wirklich mal andere Sprachen brauchst ist der Unicode normalerweise relativ schnell hinzu gefügt. Bedenke auch: Die Konsole kann nicht zwangsläufig einen UTF-8 string ausgeben! wstring etc. kannste vergessen.

    std__markus schrieb:

    Angenommen ich programmiere unter Windows und lese mit einer Funktion den Computernamen aus, auf einem deutschen PC sollte es da keine Probleme geben, doch was genau passiert wenn das Programm auf einem russischen PC ausgeführt wird? std::string kann keine kyrillischen Zeichen enthalten, demnach müsste ich std::wstring verwenden, oder? Wenn ich nun doch std::string verwendet habe, ist dieser String dann einfach ungültig und „kaputt“, oder kann man nach einer Konvertierung zu std::wstring tatsächlich noch an den Namen kommen?

    Du nutzt die Unicode-Variante der WinAPI Funktion, und wandelst dann für den Rest des Programms den String den du bekommst nach UTF-8 um. Unter Windows gibt's für sowas schon fertige Funktionen:
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130(v=vs.85).aspx
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx

    Du musst also an allen API-Grenzen zwischen UTF-8 und dem was die API will umwandeln. Das hört sich jetzt schlimm an, aber wenn die Funktion zum umwandeln ein mal geschrieben ist, ist das halt auch nur ein Funktionsaufruf mehr. Und da du natürlich alles Plattform-Unabhängig schreiben willst, musst du die ganzen API calls eh kapseln.



  • Ok, ich hoffe ich habe alles Verstanden. Also möglichst immer std::string mit UTF-8 verwenden und wenn ich ein wchar_t habe, dieses dann zu UTF-8 konvertieren.

    Ich habe auf die Schnelle folgenden Code geschrieben, bitte dieses Thema deswegen nicht in den WinAPI Bereich verschieben, das Ganze soll nur als Beispiel dienen.

    #include <iostream>
    #include <string>
    #include <memory>
    #include <Windows.h>
    
    int main()
    {
        wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
        DWORD nameSize = sizeof(computerName);
    
        if (GetComputerNameW(computerName, &nameSize))
        {
            // Unicode Ausgabe
            std::wcout << "Unicode: " << computerName << std::endl;
    
            // Nach UTF-8 umwandeln
            int multiByteSize = WideCharToMultiByte(CP_UTF8, 0, computerName, sizeof(computerName), 0, 0, NULL, NULL);
            if (multiByteSize)
            {
                std::unique_ptr<char[]> convertedName(new char[multiByteSize]);
    
                if (WideCharToMultiByte(CP_UTF8, 0, computerName, sizeof(computerName), convertedName.get(), multiByteSize, NULL, NULL))
                {
                    // UTF-8 Ausgabe
                    std::cout << "UTF-8: " << convertedName.get() << std::endl;
                }
            }
        }
    }
    

    Angenommen dieses Programm wird auf einem russischen PC ausgeführt. Ist der Computername bei beiden Ausgaben der selbe? Oder besser ausgedrückt: Ist der Inhalt beider Variablen der selbe?

    Viele Grüße
    Markus



  • Die beiden Variablen computerName und convertedName sind natürlich nicht gleich, sonst müsste man da doch nichts konvertieren. Insbesondere die Ausgabe des UTF-8 strings auf der Konsole wird nicht mal unbedingt klappen. Außerdem können auch zwei "identische" Unicode-Strings ein anderes Byte-Muster haben. Deshalb gibt es auch spezielle Funktionen, die Unicode-Strings vergleichen, oder darin nach Zeichen suchen etc. Aber wenn du einem Programm, das Unicode-Strings ausgeben kann, (z.B. einem Browser) beide Strings gibst (und jeweils das encoding mitteilst), dann wird es das gleiche ausgeben.
    PS: unique_ptr ist dafür weniger geeignet. Nimm ruhig std::string, dem kannst du auch eine feste Größe geben: std::string s(size, '\0')


Anmelden zum Antworten