Здесь есть несколько очень хороших ответов, но я думаю, что могу добавить пару вещей, касающихся Windows / Visual Studio. Это основано на моем опыте работы с VS2015. В Linux основной ответ - использовать везде в кодировке UTF-8 std::string
. В Windows / VS все становится сложнее. Вот почему. Windows ожидает, что строки, хранящиеся с использованием char
s, будут закодированы с использованием кодовой страницы языкового стандарта. Это почти всегда набор символов ASCII, за которым следуют 128 других специальных символов в зависимости от вашего местоположения. Позвольте мне просто заявить, что это не только при использовании Windows API, есть еще три основных места, где эти строки взаимодействуют со стандартным C ++. Это строковые литералы, выводимые в std::cout
с использованием <<
и передача имени файла в std::fstream
.
Скажу сразу, что я программист, а не языковый специалист. Я понимаю, что USC2 и UTF-16 не одно и то же, но для моих целей они достаточно близки, чтобы быть взаимозаменяемыми, и я использую их как таковые здесь. На самом деле я не уверен, что использует Windows, но, как правило, мне и знать не нужно. В этом ответе я указал UCS2, поэтому заранее извините, если я кого-нибудь расстрою своим незнанием этого вопроса, и я рад изменить его, если у меня что-то не так.
Строковые литералы
Если вы вводите строковые литералы, содержащие только символы, которые могут быть представлены вашей кодовой страницей, тогда VS сохраняет их в вашем файле с кодировкой 1 байт на символ на основе вашей кодовой страницы. Обратите внимание, что если вы измените свою кодовую страницу или передадите свой исходный код другому разработчику, использующему другую кодовую страницу, я думаю (но не тестировал), что персонаж будет другим. Если вы запустите свой код на компьютере с другой кодовой страницей, я не уверен, изменится ли и символ.
Если вы введете какие-либо строковые литералы, которые не могут быть представлены вашей кодовой страницей, VS попросит вас сохранить файл как Unicode. Затем файл будет закодирован как UTF-8. Это означает, что все символы, отличные от ASCII (включая те, которые находятся на вашей кодовой странице), будут представлены 2 или более байтами. Это означает, что если вы передадите свой источник кому-то другому, он будет выглядеть так же. Однако перед передачей исходного кода компилятору VS преобразует текст в кодировке UTF-8 в текст, закодированный для кодовой страницы, и любые символы, отсутствующие в кодовой странице, заменяются на ?
.
Единственный способ гарантировать правильное представление строкового литерала Unicode в VS - это поставить перед строковым литералом знак L
, что сделает его широким строковым литералом. В этом случае VS преобразует текст в кодировке UTF-8 из файла в UCS2. Затем вам нужно передать этот строковый литерал в конструктор std::wstring
или преобразовать его в utf-8 и поместить в std::string
. Или, если вы хотите, вы можете использовать функции Windows API для его кодирования, используя свою кодовую страницу, чтобы поместить его в std::string
, но тогда вы также можете не использовать широкий строковый литерал.
std :: cout
При выводе на консоль с использованием <<
вы можете использовать только std::string
, а не std::wstring
, и текст должен быть закодирован с использованием кодовой страницы вашего языкового стандарта. Если у вас есть std::wstring
, вы должны преобразовать его с помощью одной из функций Windows API, и любые символы, отсутствующие на вашей кодовой странице, будут заменены на ?
(возможно, вы можете изменить символ, я не могу вспомнить).
std :: fstream имена файлов
ОС Windows использует UCS2 / UTF-16 для имен файлов, поэтому независимо от вашей кодовой страницы вы можете иметь файлы с любым символом Unicode. Но это означает, что для доступа или создания файлов с символами, которых нет на вашей кодовой странице, вы должны использовать std::wstring
. Другого пути нет. Это специальное расширение Microsoft для std::fstream
, поэтому, вероятно, не будет компилироваться в других системах. Если вы используете std :: string, вы можете использовать только те имена файлов, которые содержат только символы на вашей кодовой странице.
Ваши варианты
Если вы просто работаете над Linux, то вы, вероятно, не зашли так далеко. Просто используйте везде UTF-8 std::string
.
Если вы просто работаете в Windows, просто везде используйте UCS2 std::wstring
. Некоторые пуристы могут сказать, что используйте UTF8, а затем конвертируйте, когда это необходимо, но зачем возиться с этими хлопотами.
Если вы кроссплатформенный, то, честно говоря, это беспорядок. Если вы пытаетесь использовать UTF-8 везде в Windows, вам нужно быть очень осторожным со строковыми литералами и выводом на консоль. Вы можете легко испортить там свои строки. Если вы используете std::wstring
везде в Linux, у вас может не быть доступа к широкой версии std::fstream
, поэтому вам придется выполнить преобразование, но риск повреждения отсутствует. Так что лично я считаю, что это лучший вариант. Многие не согласятся, но я не одинок - это, например, путь, по которому идут wxWidgets.
Другой вариант - ввести unicodestring
как std::string
в Linux и std::wstring
в Windows и иметь макрос под названием UNI () с префиксом L в Windows и ничего в Linux, затем код
#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>
#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
std::string result;
//Call WideCharToMultiByte to do the conversion
return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
return str;
}
#endif
int main()
{
unicodestring fileName(UNI("fileName"));
std::ofstream fout;
fout.open(fileName);
std::cout << formatForConsole(fileName) << std::endl;
return 0;
}
я думаю, будет хорошо на любой платформе.
Ответы
Итак, чтобы ответить на ваши вопросы
1) Если вы программируете для Windows, то все время, если кросс-платформенный, то, возможно, все время, если вы не хотите иметь дело с возможными проблемами повреждения в Windows или писать код для конкретной платформы #ifdefs
, чтобы обойти различия, если только используя линукс тогда никогда.
2) Да. Кроме того, в Linux вы также можете использовать его для всех Unicode. В Windows вы можете использовать его только для всего Юникода, если вы выберете ручное кодирование с использованием UTF-8. Но Windows API и стандартные классы C ++ ожидают, что std::string
будет закодирован с использованием кодовой страницы локали. Сюда входят все символы ASCII плюс еще 128 символов, которые меняются в зависимости от кодовой страницы, для которой настроен ваш компьютер.
3) Я так считаю, но если нет, то это просто определение типа 'std :: basic_string' с использованием wchar_t
вместо char
4) Широкий символ - это тип символа, размер которого больше, чем стандартный тип char
, равный 1 байту. В Windows это 2 байта, в Linux - 4 байта.
person
Phil Rosenberg
schedule
17.08.2018