Я создал этот минимальный рабочий фрагмент примера C++ для сравнения байтов (по их шестнадцатеричному представлению) в std::string
и std::wstring
при определении строки с немецкими символами, отличными от ASCII, в любом типе.
#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;
}
Вывод этого фрагмента
c3 a4 c3 b6 c3 bc c3 9f
00c3 00a4 00c3 00b6 00c3 00bc 00c3 0178
Я запустил это на ПК под управлением 64-разрядной версии Windows 10 Pro, скомпилировал с помощью MSVC 2019 Community Edition в версии 16.8.1, используя систему сборки cmake. strong> с последующим CMakeLists.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)
Я читал, что std::string
основаны на типе char
, который представляет собой один байт. Я вижу, что вывод моего фрагмента указывает на то, что str
(переменная std::string
) имеет кодировку UTF-8. Я читал, что компиляторы Microsoft используют wchar_t
s с 2 байтами для создания std::wstring
s (вместо 4-байтовых wchar_t
s, например, GNU gcc) и поэтому ожидают, что wstr
(переменная std::wstring
) будет (любым) UTF-16 закодировано. Но я не могу понять, почему ß (латинское диез s) кодируется как 0x00c30178
, вместо этого я ожидал 0x00df
. Может кто-нибудь, пожалуйста, скажите мне:
- Почему это происходит?
- Как я могу получить
std::wstring
s в кодировке UTF-16 (Big Endian подойдет, я не возражаю против спецификации)? Мне, наверное, нужно как-то сообщить компилятору? - Что это за кодировка?
РЕДАКТИРОВАТЬ 1
изменил заголовок, так как он не соответствовал вопросам должным образом (и на самом деле UTF-8 и UTF-16 - это разные кодировки, поэтому я уже сам ответил на новый ответ...)
РЕДАКТИРОВАТЬ 2
забыл упомянуть: я использую цель amd64
упомянутого компилятора
РЕДАКТИРОВАТЬ 3
если добавить флаг /utf-8
, как указано в комментариях dxiv (см. его связанный SO-Post), я получаю желаемое вывод
c3 a4 c3 b6 c3 bc c3 9f
00e4 00f6 00fc 00df
который для меня выглядит как UTF-16-BE (без спецификации). Поскольку у меня были проблемы с правильным порядком команд cmake, это мой текущий файл CmakeLists.txt
. Важно поставить команду add_compile_options
перед командой add_executable
(для удобства я добавил Уведомление)
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)
Я нахожу способ if-endif
более читаемым, чем вариант с синтаксисом генератора, но запись add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
вместо этого тоже сработает.
Примечание. Для Qt-Projects есть хороший переключатель для файла .pro
(см. это сообщение Qt-Form)
win32 {
QMAKE_CXXFLAGS += /utf-8
}
Тем не менее, первая часть моего вопроса открыта: какая кодировка 0x00c30178
для ß (латинское диез s)?
main.cpp
закодирован в UTF-8, HxD показывает мнеC3 A4 C3 B6 C3 BC C3 9F
для обеих строк. Я использую код Visual Studio с расширением CMake Tools для создания проекта и его редактирования. Но я получаю тот же результат, используя Qt Creator. - person Martin   schedule 30.11.2020/source-charset:utf-8
? - person dxiv   schedule 30.11.20200x23
, что означает #. По поводуsource-charset
нет, если cmake не устанавливает его автоматически. Я используюCMakeLists.txt
. Как я могу установить это с помощью cmake? - person Martin   schedule 01.12.20200x00c30178
, но если вы опубликуете свой комментарий в качестве ответа, я отмечу его как правильный. - person Martin   schedule 01.12.2020ß
--›0xC3 0x9F
--›U+00C3 U+0178
. - person dxiv   schedule 01.12.2020U+FEFF
, поэтому вы можете определить используемую UTF, посмотрев на спецификацию - person Remy Lebeau   schedule 04.12.2020