Wie wird const std :: wstring codiert und wie wird zu UTF-16 gewechselt?

Nov 30 2020

Ich habe dieses minimal funktionierende C ++ - Beispiel-Snippet erstellt, um Bytes (anhand ihrer Hex-Darstellung) in a std::stringund a zu vergleichen, std::wstringwenn eine Zeichenfolge mit deutschen Nicht-ASCII-Zeichen in beiden Typen definiert wird.

#include <iostream>
#include <iomanip>
#include <string>

int main(int, char**) {
    std::wstring wstr = L"äöüß";
    std::string str = "äöüß";

    for ( unsigned char c : str ) {
        std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned short>(c) << ' ';
    }
    std::cout << std::endl;

    for ( wchar_t c : wstr ) {
        std::cout << std::setw(4) << std::setfill('0') << std::hex << static_cast<unsigned short>(c) << ' ';
    }
    std::cout << std::endl;

    return 0;
}

Die Ausgabe dieses Snippets ist

c3 a4 c3 b6 c3 bc c3 9f 
00c3 00a4 00c3 00b6 00c3 00bc 00c3 0178

Ich habe dies auf einem PC ausgeführt, auf dem Windows 10 64-Bit Pro ausgeführt wird , und mit MSVC 2019 Community Edition in Version 16.8.1 kompiliert, wobei das Build-System cmake wie folgt verwendet wurdeCMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)
project(wstring VERSION 0.1.0)

set(CMAKE_CXX_STANDARD 17)

include(CTest)
enable_testing()

add_executable(wstring main.cpp)

set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

Ich habe gelesen, dass std::strings auf dem charTyp basiert, der ein einzelnes Byte ist. Ich sehe, dass die Ausgabe meines Snippets anzeigt, dass str(die std::stringVariable) UTF-8- codiert ist. Ich habe gelesen, dass Microsoft-Compiler wchar_ts mit 2 Bytes verwenden, um std::wstrings zu bilden (anstelle von 4 Bytes, wchar_tz. B. GNU gcc), und daher erwarten würden, dass wstr(die std::wstringVariable) (jede Art von) UTF-16- codiert wird. Aber ich kann nicht herausfinden, warum das "ß" (lateinisch scharf) so codiert ist, wie 0x00c30178ich es 0x00dfstattdessen erwartet hatte . Darf mir bitte jemand sagen:

  • Warum passiert das?
  • Wie kann ich mit UTF-16-codierten std::wstrings enden (Big Endian wäre in Ordnung, mir macht eine Stückliste nichts aus)? Muss ich es dem Compiler wahrscheinlich irgendwie sagen?
  • Was für eine Kodierung ist das?

BEARBEITEN 1

Der Titel wurde geändert, da er nicht richtig zu den Fragen passte (und tatsächlich sind UTF-8 und UTF-16 unterschiedliche Codierungen, so dass ich selbst die Antwort bereits neu ...).

BEARBEITEN 2

vergessen zu erwähnen: Ich benutze das amd64Ziel des genannten Compilers

BEARBEITEN 3

Wenn ich das /utf-8Flag hinzufüge, wie in den Kommentaren von dxiv angegeben (siehe seinen verlinkten SO-Post ), erhalte ich die gewünschte Ausgabe

c3 a4 c3 b6 c3 bc c3 9f
00e4 00f6 00fc 00df

Das sieht für mich nach UTF-16-BE (keine Stückliste) aus. Da ich Probleme mit der richtigen Reihenfolge der cmake-Befehle hatte, ist dies meine aktuelle CmakeLists.txtDatei. Es ist wichtig, den add_compile_optionsBefehl vor den add_executableBefehl zu stellen (ich habe den Hinweis zur Vereinfachung hinzugefügt).

cmake_minimum_required(VERSION 3.0.0)
project(enctest VERSION 0.1.0)

set(CMAKE_CXX_STANDARD 17)

include(CTest)
enable_testing()

if (MSVC)
  message(NOTICE "compiling with MSVC")
  add_compile_options(/utf-8)
endif()

add_executable(enctest main.cpp)

set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

Ich finde den if-endifWeg besser lesbar als die Generator-Syntax, aber das Schreiben würde auch funktionieren.add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")

Hinweis: Für Qt-Projekte gibt es einen schönen Schalter für die .proDatei (siehe diesen Qt-Form-Beitrag ).

win32 {
    QMAKE_CXXFLAGS += /utf-8
}

Der erste Teil meiner Frage ist noch offen: Welche Kodierung ist 0x00c30178für "ß" (lateinisch scharf s)?

Antworten

5 dxiv Dec 01 2020 at 16:41

Wie in den Kommentaren erläutert, ist die Quelldatei .cppUTF-8-codiert. Ohne Stückliste und ohne expliziten /source-charset:utf-8Wechsel geht der Visual C ++ - Compiler standardmäßig davon aus, dass die Quelldatei in der aktiven Codepage-Codierung gespeichert ist. Aus der Dokumentation zum Set Source Character Set :

Standardmäßig erkennt Visual Studio eine Markierung für die Bytereihenfolge, um festzustellen, ob die Quelldatei in einem codierten Unicode-Format vorliegt, z. B. UTF-16 oder UTF-8. Wenn keine Markierung für die Bytereihenfolge gefunden wird, wird davon ausgegangen, dass die Quelldatei mit der aktuellen Benutzercodepage codiert ist, es sei denn, Sie geben einen Zeichensatznamen oder eine Codepage mit der Option / source-charset an.

Die UTF-8-Codierung von äöüßist C3 A4 C3 B6 C3 BC C3 9Fund daher die Zeile:

    std::wstring wstr = L"äöüß";

wird vom Compiler gesehen als:

    std::wstring wstr = L"\xC3\xA4\xC3\xB6\xC3\xBC\xC3\x9F"`;

Unter der Annahme, dass die aktive Codepage das übliche Windows-1252 ist , werden die (erweiterten) Zeichen wie folgt zugeordnet:

    win-1252    char    unicode

      \xC3       Ã       U+00C3
      \xA4       ¤       U+00A4
      \xB6       ¶       U+00B6
      \xBC       ¼       U+00BC
      \x9F       Ÿ       U+0178

Daher L"\xC3\xA4\xC3\xB6\xC3\xBC\xC3\x9F"wird übersetzt in:

    std::wstring wstr = L"\u00C3\u00A4\u00C3\u00B6\u00C3\u00BC\u00C3\u0178"`;

Um eine solche (falsche) Übersetzung zu vermeiden, muss Visual C ++ mitgeteilt werden, dass die Quelldatei als UTF-8 codiert wird, indem ein expliziter /source-charset:utf-8(oder /utf-8) Compiler-Schalter übergeben wird. Bei CMake-basierten Projekten kann dies add_compile_optionswie unter Möglich gezeigt durchgeführt werden , um CMake / MSVC zu zwingen, die UTF-8-Codierung für Quelldateien ohne Stückliste zu verwenden. C4819 .

MarshallClow Nov 30 2020 at 20:50

Daher würde ich erwarten, dass wstr (die Variable std :: wstring) (jede Art von) UTF-16-codiert ist

std::wstringgibt keine Codierung an. Es ist eine Folge von "breiten Zeichen" für eine Art von breiten Zeichen (die durch die Implementierung definiert sind).

In der Standardbibliothek sind Konvertierungsfacetten für die Konvertierung in / von verschiedenen Codierungen definiert.