Здесь есть несколько очень хороших ответов, но я думаю, что могу добавить пару вещей относительно 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
. Или, если вы хотите, вы можете использовать функции API Windows для кодирования, используя кодовую страницу, чтобы поместить его в a std::string
, но тогда вы, возможно, также не использовали широкий строковый литерал.
станд :: соиЬ
При выводе на консоль с помощью <<
вы можете использовать только 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.
Другим вариантом может быть typedef, 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
чтобы обойти различия, если просто используете Linux тогда никогда.
2) Да. В дополнение к Linux вы можете использовать его для всех Unicode тоже. В Windows вы можете использовать его только для всех Unicode, если вы решите вручную кодировать с использованием UTF-8. Но Windows API и стандартные классы C ++ будут ожидать, что они std::string
будут закодированы с использованием кодовой страницы локали. Это включает в себя все ASCII плюс еще 128 символов, которые меняются в зависимости от кодовой страницы, которую ваш компьютер настроил для использования.
3) Я верю в это, но если нет, то это просто определение типа std :: basic_string с использованием wchar_t
вместоchar
4) Широкий символ - это тип символа, который больше стандартного char
типа в 1 байт . В Windows это 2 байта, в Linux это 4 байта.